From c4e73025671fc52fbe7c41b88f1a7413433c7254 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 1 Oct 2026 23:43:34 +0300 Subject: [PATCH] Add new tests and implement frame budget management - Introduced `civilization_benchmark.gd` and `legacy_quantity_math.gd` for benchmarking and legacy quantity calculations. - Created `test_dynamic_math.gd`, `test_frame_evolution.gd`, and `test_sparse_batches.gd` to validate mathematical operations and frame evolution logic. - Implemented `frame_budget.gd` to manage cooperative work on the main thread, ensuring no partially calculated state is published. - Added UID files for all new scripts to maintain unique identifiers. --- autoload/save_manager.gd | 35 ++- stage/stage.gd | 8 +- tests/README.md | 50 ++++ tests/benchmark_civilizations.gd | 74 +++++ tests/benchmark_civilizations.gd.uid | 1 + tests/benchmark_saved_state.gd | 4 +- tests/benchmark_speed6.gd | 40 +++ tests/benchmark_speed6.gd.uid | 1 + tests/benchmark_ui_speed6.gd | 56 ++++ tests/benchmark_ui_speed6.gd.uid | 1 + tests/fixtures/benchmark_ui_stage.gd | 19 ++ tests/fixtures/benchmark_ui_stage.gd.uid | 1 + tests/fixtures/big_integer_oracle.json | 1 + tests/fixtures/civilization_benchmark.gd | 30 ++ tests/fixtures/civilization_benchmark.gd.uid | 1 + tests/fixtures/legacy_quantity_math.gd | 59 ++++ tests/fixtures/legacy_quantity_math.gd.uid | 1 + tests/test_async_save.gd | 13 + tests/test_civilization_evolution.gd | 2 +- tests/test_civilization_state.gd | 4 +- tests/test_descriptions.gd | 2 +- tests/test_dynamic_math.gd | 72 +++++ tests/test_dynamic_math.gd.uid | 1 + tests/test_exact_math.gd | 2 +- tests/test_frame_evolution.gd | 100 +++++++ tests/test_frame_evolution.gd.uid | 1 + tests/test_life.gd | 4 +- tests/test_quantity_catalog.gd | 48 +++ tests/test_short_lived_events.gd | 20 +- tests/test_sparse_batches.gd | 52 ++++ tests/test_sparse_batches.gd.uid | 1 + tests/test_stellar_rules.gd | 6 +- tests/test_time.gd | 4 +- tests/test_world_indicators.gd | 2 +- ui/owniverse_item/owniverse_item.gd | 3 +- world/owniverse/automatic_production.gd | 6 +- world/owniverse/civilization_evolution.gd | 46 ++- world/owniverse/civilization_state.gd | 115 ++++---- world/owniverse/entity_catalog.gd | 50 ++++ world/owniverse/evolution_coordinator.gd | 61 +++- world/owniverse/frame_budget.gd | 22 ++ world/owniverse/frame_budget.gd.uid | 1 + world/owniverse/item_description.gd | 2 +- world/owniverse/math/README.md | 128 +++----- world/owniverse/math/big_integer.gd | 23 ++ world/owniverse/math/exact.gd | 293 +++++++++---------- world/owniverse/math/exact_value.gd | 11 +- world/owniverse/object_batches.gd | 37 ++- world/owniverse/object_ledger.gd | 16 +- world/owniverse/owniverse.gd | 83 +++++- world/owniverse/quantity_math.gd | 73 +++-- world/owniverse/universe_environment.gd | 12 + world/owniverse/world_parameters.gd | 12 +- 53 files changed, 1313 insertions(+), 397 deletions(-) create mode 100644 tests/benchmark_civilizations.gd create mode 100644 tests/benchmark_civilizations.gd.uid create mode 100644 tests/benchmark_speed6.gd create mode 100644 tests/benchmark_speed6.gd.uid create mode 100644 tests/benchmark_ui_speed6.gd create mode 100644 tests/benchmark_ui_speed6.gd.uid create mode 100644 tests/fixtures/benchmark_ui_stage.gd create mode 100644 tests/fixtures/benchmark_ui_stage.gd.uid create mode 100644 tests/fixtures/big_integer_oracle.json create mode 100644 tests/fixtures/civilization_benchmark.gd create mode 100644 tests/fixtures/civilization_benchmark.gd.uid create mode 100644 tests/fixtures/legacy_quantity_math.gd create mode 100644 tests/fixtures/legacy_quantity_math.gd.uid create mode 100644 tests/test_dynamic_math.gd create mode 100644 tests/test_dynamic_math.gd.uid create mode 100644 tests/test_frame_evolution.gd create mode 100644 tests/test_frame_evolution.gd.uid create mode 100644 tests/test_sparse_batches.gd create mode 100644 tests/test_sparse_batches.gd.uid create mode 100644 world/owniverse/frame_budget.gd create mode 100644 world/owniverse/frame_budget.gd.uid diff --git a/autoload/save_manager.gd b/autoload/save_manager.gd index 2c6fb55..2e10adb 100644 --- a/autoload/save_manager.gd +++ b/autoload/save_manager.gd @@ -6,7 +6,7 @@ const E = preload("res://world/owniverse/math/exact.gd") const SETTING_SECTION = "Settings" const SAVE_PATH = "user://settings.cfg" -const FORMAT_VERSION : int = 4 +const FORMAT_VERSION : int = 5 const SimulationTime = preload("res://world/owniverse/simulation_time.gd") const WorldParameters = preload("res://world/owniverse/world_parameters.gd") const STATE_VERSION : String = SimulationTime.STATE_VERSION @@ -35,7 +35,7 @@ func _snapshot(filename: String, password: String, data: Dictionary) -> Dictiona var payload: Dictionary = E.encode(data) payload.format_version = FORMAT_VERSION payload.app_version = str(ProjectSettings.get_setting("application/config/version", "")) - return {"filename": filename, "path": save_directory.path_join(E.add(filename, ".adventure")), "password": password, "payload": payload, "plaintext": Global.save_plaintext_copy, "speed_limit": Global.SPEED_LIMIT, "stages": Global.CivilizationRules.keys()} + return {"filename": filename, "path": save_directory.path_join(E.add(filename, ".adventure")), "password": password, "payload": payload, "plaintext": Global.save_plaintext_copy, "speed_limit": Global.SPEED_LIMIT, "stages": Global.CivilizationRules.keys(), "entities": Global.OwniverseEntities.keys()} ## True means queued, not written. Completion is reported by save_completed. @@ -105,7 +105,7 @@ func save_data(filename: String, password: String, data: Dictionary) -> bool: static func _write_snapshot(job: Dictionary) -> String: var payload: Dictionary = job.payload - var problem: String = _validate_payload(payload, job.speed_limit, job.stages) + var problem: String = _validate_payload(payload, job.speed_limit, job.stages, job.entities) if E.ne(problem, ""): return E.add("Invalid save: ", problem) var path: String = job.path @@ -207,17 +207,17 @@ static func _plain_tree(value: Variant) -> bool: ## Return a diagnostic path on failure; an empty string means the structure is valid. func validate_data(data: Variant) -> String: - return _validate_payload(data, Global.SPEED_LIMIT, Global.CivilizationRules.keys()) + return _validate_payload(data, Global.SPEED_LIMIT, Global.CivilizationRules.keys(), Global.OwniverseEntities.keys()) -static func _validate_payload(data: Variant, speed_limit: int, stages: Array) -> String: +static func _validate_payload(data: Variant, speed_limit: int, stages: Array, entities: Array) -> String: if not E.valid_encoded(data): return "invalid exact number encoding" data = E.decode(data) if ((not (data is Dictionary)) or (not _plain_tree(data))): return "save must contain plain finite values" if (E.ne(data.get("format_version"), FORMAT_VERSION) or (not (data.get("app_version") is String))): return "unsupported save format" - if (((not (data.get("ui") is Dictionary)) or (not (data.ui.get("current_page") is int))) or E.lt(data.ui.current_page, 0)): + if (((not (data.get("ui") is Dictionary)) or (not E.numeric(data.ui.get("current_page")))) or E.lt(data.ui.current_page, 0)): return "invalid ui.current_page" if (not (data.get("state") is Dictionary)): return "state must be a Dictionary" @@ -258,6 +258,29 @@ static func _validate_payload(data: Variant, speed_limit: int, stages: Array) -> return "invalid state.speed" if ((not _number(saved.speed_in_year)) or E.ne(saved.speed_in_year, E.power(10, E.subtract(saved.speed, 1)))): return "invalid state.speed_in_year" + if data.has("simulation"): + var checkpoint: Variant = data.simulation + if not checkpoint is Dictionary or not checkpoint.get("productions") is Array: + return "invalid simulation checkpoint" + if not _number(checkpoint.get("speed"), true) or E.lt(checkpoint.speed, 1) or E.gt(checkpoint.speed, speed_limit): + return "invalid simulation speed" + for name in ["requested_clock", "active_clock"]: + var clock: Variant = checkpoint.get(name) + if not clock is Dictionary: return "invalid simulation clock" + if clock.is_empty(): continue + if not _number(clock.get("datetime")) or not _number(clock.get("year")): + return "invalid simulation clock" + if E.lt(clock.datetime, saved.time.datetime) or E.ne(clock.year, SimulationTime.processed_year(clock.datetime)): + return "invalid simulation clock" + if not E.finite(clock.get("tick_remainder", 0)) or E.ge(E.absolute(clock.get("tick_remainder", 0)), 1): + return "invalid simulation tick" + if not checkpoint.active_clock.is_empty(): + if checkpoint.requested_clock.is_empty() or E.gt(checkpoint.active_clock.datetime, checkpoint.requested_clock.datetime): + return "invalid simulation clock order" + for command in checkpoint.productions: + if not command is Dictionary or not entities.has(command.get("id")) or not command.get("resource") is bool or not _number(command.get("amount")): + return "invalid queued production" + if command.resource and command.id not in ["S", "H"]: return "invalid queued resource production" if ((not _number(saved.energy, true)) or (not _number_map(saved.amount, true))): return "invalid state resources" if ((not (saved.stats is Dictionary)) or (not _number_map(saved.stats.get("total_amount"), true))): diff --git a/stage/stage.gd b/stage/stage.gd index c685788..7bdf091 100644 --- a/stage/stage.gd +++ b/stage/stage.gd @@ -219,7 +219,7 @@ func item_activated(item: OwniverseItem) -> void: if item.item_id == "S" or item.item_id == "H": var _value = owniverse.state.amount[item.item_id] _value = E.multiply(9, _value) if E.gt(_value, 0) else 1 - owniverse.production.produce_hs(item.item_id, _value) + owniverse.request_production(item.item_id, _value, true) func _check_counters(delta: float) -> Array: @@ -302,7 +302,7 @@ func _page_action_pressed(page_id: int, action_amount) -> void: var item_id: String = g_active_items[page_id].item_id if E.gt(action_amount, 0): - owniverse.production.produce(item_id, action_amount) + owniverse.request_production(item_id, action_amount) #endregion @@ -369,7 +369,7 @@ func _refresh_universe_ui() -> void: func _process(delta: float) -> void: - owniverse.evolute(delta) + owniverse.evolute_frame(delta, get_tree()) indicator_elapsed += delta if indicator_elapsed >= 0.1: indicator_elapsed = 0.0 @@ -449,6 +449,7 @@ func load_data() -> bool: var complete: Dictionary = owniverse.state.duplicate(true) complete.merge(restored, true) owniverse.state = complete + owniverse.restore_frame_checkpoint(game_data.get("simulation", {})) owniverse.evolution.initialize_life_batches() owniverse.presentation.refresh(owniverse.state, owniverse.catalog) @@ -471,6 +472,7 @@ func save_data() -> void: page = clampi(roundi(float(stage_page_scroller.scroll_horizontal) / PAGE_WIDTH), 0, PAGE_COUNT - 1) SaveManager.request_save("owniverse", "qwerty", { "state": owniverse.state, + "simulation": owniverse.frame_checkpoint(), "ui": {"current_page": page}, }) diff --git a/tests/README.md b/tests/README.md index 4fdd216..26aecfc 100644 --- a/tests/README.md +++ b/tests/README.md @@ -155,3 +155,53 @@ godot --headless --path Owniverse.GI --script res://tests/test_civilization_evol ``` Проверяются реальные коэффициенты C0.2, войны и побочный ущерб C2.0, замена планет колониями с сохранением хозяина, дипломатическое влияние, бонус периода от структур и деградация при их отсутствии. Ускоренная модель проходит все стадии C0.2 → C4.4 → Ct. Проверки контролируют сохранение населения, целочисленность этик, валидацию сохранения и детерминированное продолжение после сериализации. + +## Профиль цивилизаций на шестой скорости + +```sh +godot --headless --path Owniverse.GI --script res://tests/benchmark_civilizations.gd -- frames=20 profile +godot --path Owniverse.GI --script res://tests/benchmark_civilizations.gd -- ui scenario=mixed frames=10 profile +``` + +Сценарии `mixed`, `large`, `fragmented` заполняют все стадии и этики, синхронизируя +переходы; `large` использует по 6e20 цивилизаций, `fragmented` — десять партий. +Это искусственные стрессовые сценарии. `scenario=stable` использует штатные +сроки стадий. Параметр `snapshot=/tmp/civil` сохраняет состояние каждого сценария +для сравнения до и после изменения. UI запускает настоящую сцену со страницей +жизни и реальным delta, без загрузки и записи сохранения игрока. + +`profile` выводит суммарные микросекунды и число вызовов по этапам. Вложенные +этапы входят во время родительских; складывать их нельзя. В игре сбор выключен. +Кэши физических количеств принадлежат отдельному миру и проверяют изменения +количеств, вложенных привязок и индексов каталога. Кэш структуры правил не входит +в сохранение: при изменении Claim/бонусов нужно перестроить индексы каталога, +при изменении home в существующей таблице — invalidate_civilization_layout(). + +После оптимизации на M4 Pro, по 20 шагов 1/60 секунды, среднее время: +`mixed` 295 → 235 мс, `large` 666 → 539 мс, `fragmented` 359 → 282 мс. +Полные состояния всех трёх сценариев после 20 шагов совпали до и после изменения. +Дополнительно тест распределений сравнивает новый путь с прежним на 300 +случайных наборах, включая 1e40 и накопленные долги округления. + +## Расчёт между кадрами + +`godot --headless --path Owniverse.GI --script res://tests/test_frame_evolution.gd` + +Stage вызывает `evolute_frame`: транзакция получает бюджет 40 мс и уступает +следующему кадру внутри создания партий и обработки стадий. Расчёт остаётся +на главном потоке, состояние публикуется только после полного завершения. +Длительность одной транзакции ограничена обычным шагом 1/60 секунды выбранной +скорости. Запрошенное время хранится отдельно, поэтому отставание не превращается +в один всё более тяжёлый шаг. При предельной нагрузке время симуляции может +отставать от запрошенного; это не ограничение FPS интерфейса и не удаление событий. + +Производство во время транзакции выполняется после её завершения. Запрошенное +время, активный интервал, скорость и очередь производства входят в сохранение; +при загрузке незавершённый интервал пересчитывается с опубликованного состояния. +Сброс мира отменяет отложенный расчёт. Тест проверяет точное совпадение непрерывного +и распределённого расчёта, очереди, переключение скорости, восстановление и отмену. + +На M4 Pro, 180 кадров реального UI на шестой скорости: смешанный сценарий +15.9 FPS (максимальный кадр 98 мс), большие количества 17.5 FPS (106 мс), +много партий 16.3 FPS (97 мс). +Это FPS отрисовки, а не число завершённых транзакций симуляции в секунду. diff --git a/tests/benchmark_civilizations.gd b/tests/benchmark_civilizations.gd new file mode 100644 index 0000000..c3df1ad --- /dev/null +++ b/tests/benchmark_civilizations.gd @@ -0,0 +1,74 @@ +extends SceneTree +const Fixture = preload("res://tests/fixtures/civilization_benchmark.gd") + +func _initialize(): call_deferred("run") + +func run(): + var ui: bool = "ui" in OS.get_cmdline_user_args() + var scenarios: Array = ["mixed", "large", "fragmented"] + var frames: int = 120 + var step_delta: float = 1.0 / 60.0 + for argument in OS.get_cmdline_user_args(): + if argument.begins_with("scenario="): scenarios = [argument.trim_prefix("scenario=")] + if argument.begins_with("delta="): step_delta = float(argument.trim_prefix("delta=")) + if argument.begins_with("frames="): frames = maxi(2, int(argument.trim_prefix("frames="))) + Engine.max_fps = 60 + if ui: DisplayServer.window_set_size(Vector2i(540, 960)) + for scenario in scenarios: + var scene + var stage + var world + if ui: + scene = load("res://world/world.tscn").instantiate() + stage = scene.get_node("Stage") + stage.owniverse.free() + stage.set_script(load("res://tests/fixtures/benchmark_ui_stage.gd")) + root.add_child(scene) + await process_frame + await process_frame + world = stage.owniverse + else: + world = load("res://world/owniverse/owniverse.gd").new() + world.catalog.load_definitions(root.get_node("Global").OwniverseEntities) + Fixture.seed(world, root.get_node("Global"), scenario == "fragmented", scenario == "large", scenario == "stable") + world.profile_enabled = "profile" in OS.get_cmdline_user_args() + var samples: Array = [] + if ui: + stage.stage_page_scroller.scroll_horizontal = 4 * stage.PAGE_WIDTH + for item in stage.owniverse_items.values(): item.visible = true + for page in stage.item_pages: page.visible = true + stage._set_item_description(stage.owniverse_items["C2.0"]) + stage._refresh_universe_ui() + for warmup in 10: await process_frame + stage.measuring = true + for frame in frames: + await process_frame + if (frame + 1) % 10 == 0: + print("%s: measured %d UI frames" % [scenario, frame + 1]) + stage.measuring = false + samples = stage.process_samples + report(scenario + " UI frame", stage.frame_samples) + else: + for frame in frames: + var started: int = Time.get_ticks_usec() + world.evolute(step_delta) + samples.append((Time.get_ticks_usec() - started) / 1000.0) + report(scenario + (" UI handler" if ui else " CPU"), samples) + if ui: + print("Completed simulation transactions: ", world.frame_commits, "; published year: ", world.state.time.year, "; requested year: ", world.frame_clock.get("year", 0)) + print("Statistics ", world.state.civilization_stats) + if world.profile_enabled: print("Profile microseconds/calls: ", world.profile) + for argument in OS.get_cmdline_user_args(): + if argument.begins_with("snapshot="): + var file = FileAccess.open(argument.trim_prefix("snapshot=") + "-" + scenario + ".json", FileAccess.WRITE) + file.store_string(JSON.stringify(world.E.encode(world.state))) + for entity in world.catalog.entities.values(): entity.free() + world.free() + if ui: scene.free() + quit() + +func report(label: String, samples: Array): + var total: float = 0.0 + for sample in samples: total += sample + samples.sort() + print("%s: mean %.2f ms, p95 %.2f ms, max %.2f ms, %.1f per second" % [label, total / samples.size(), samples[ceili(samples.size() * 0.95) - 1], samples.back(), samples.size() * 1000 / total]) diff --git a/tests/benchmark_civilizations.gd.uid b/tests/benchmark_civilizations.gd.uid new file mode 100644 index 0000000..d4c35dd --- /dev/null +++ b/tests/benchmark_civilizations.gd.uid @@ -0,0 +1 @@ +uid://b5w4sp6eepypa diff --git a/tests/benchmark_saved_state.gd b/tests/benchmark_saved_state.gd index 30e8441..83382c3 100644 --- a/tests/benchmark_saved_state.gd +++ b/tests/benchmark_saved_state.gd @@ -22,8 +22,8 @@ func run(): quit(1) return var data = JSON.parse_string(FileAccess.get_file_as_string(args[0])) - if not data is Dictionary or data.get("format_version") != 4: - push_error("Expected diagnostic JSON format 4") + if not data is Dictionary or data.get("format_version") != 5: + push_error("Expected diagnostic JSON format 5") quit(1) return var initial: Dictionary = E.decode(restore_json_integers(data)).state diff --git a/tests/benchmark_speed6.gd b/tests/benchmark_speed6.gd new file mode 100644 index 0000000..09c1507 --- /dev/null +++ b/tests/benchmark_speed6.gd @@ -0,0 +1,40 @@ +extends SceneTree +const E = preload("res://world/owniverse/math/exact.gd") + +func _initialize(): call_deferred("run") + +func run(): + for scenario in ["ordinary", "hypergiants"]: + var world = load("res://world/owniverse/owniverse.gd").new() + world.catalog.load_definitions(root.get_node("Global").OwniverseEntities) + for id in world.catalog.entities: + world.state.amount[id] = 0 + world.state.stats.total_amount[id] = 0 + var group: String = world.catalog.entities[id].group_as + if group != "": + world.state.amount[group] = 0 + world.state.stats.total_amount[group] = 0 + world.speed = 6 + world.state.amount.S = E.of("1e24") + world.state.amount.H = E.of("1e24") + for entry in [["RD", 1234567], ["YD", 765432], ["STN", 654321]]: + world.state.amount[entry[0]] = entry[1] + world.batches.append_batch(world.state, entry[0], entry[1], 0, 0) + if scenario == "hypergiants": + world.state.amount.HG = E.of("1e20") + world.batches.append_batch(world.state, "HG", E.of("1e20"), 0, 0) + var start_year = E.subtract(world.catalog.entities.HG.lifespan, 1000) + world.state.time = {"datetime": start_year, "year": start_year} + var samples: Array = [] + var total: int = 0 + for frame in 600: + var started: int = Time.get_ticks_usec() + world.evolute(1.0 / 60.0) + var duration: int = Time.get_ticks_usec() - started + samples.append(duration) + total += duration + samples.sort() + print("Speed 6 %s: 600 frames, mean %.3f ms, p95 %.3f ms, max %.3f ms, %.1f cycles/sec" % [scenario, total / 600000.0, samples[569] / 1000.0, samples.back() / 1000.0, 600000000.0 / total]) + for entity in world.catalog.entities.values(): entity.free() + world.free() + quit() diff --git a/tests/benchmark_speed6.gd.uid b/tests/benchmark_speed6.gd.uid new file mode 100644 index 0000000..98c78d6 --- /dev/null +++ b/tests/benchmark_speed6.gd.uid @@ -0,0 +1 @@ +uid://bboo6op14es24 diff --git a/tests/benchmark_ui_speed6.gd b/tests/benchmark_ui_speed6.gd new file mode 100644 index 0000000..3d236ac --- /dev/null +++ b/tests/benchmark_ui_speed6.gd @@ -0,0 +1,56 @@ +extends SceneTree +const E = preload("res://world/owniverse/math/exact.gd") + +func _initialize(): call_deferred("run") + +func report(label: String, samples: Array): + var total: float = 0.0 + var slow: int = 0 + for sample in samples: + total += sample + if sample > 33.333: slow += 1 + samples.sort() + print("%s: %d samples, mean %.3f ms, p95 %.3f ms, max %.3f ms, >33ms %d" % [label, samples.size(), total / samples.size(), samples[int(samples.size() * 0.95) - 1], samples.back(), slow]) + +func run(): + Engine.max_fps = 60 + DisplayServer.window_set_size(Vector2i(540, 960)) + print("Renderer: ", RenderingServer.get_current_rendering_method(), " adapter: ", RenderingServer.get_video_adapter_name()) + for scenario in ["ordinary", "hypergiants"]: + for page in ([2] if "stars" in OS.get_cmdline_user_args() else [1, 2]): + var scene = load("res://world/world.tscn").instantiate() + var stage = scene.get_node("Stage") + stage.owniverse.free() + stage.set_script(load("res://tests/fixtures/benchmark_ui_stage.gd")) + root.add_child(scene) + await process_frame + await process_frame + var world = stage.owniverse + world.speed = 6 + world.state.amount.S = E.of("1e24") + world.state.amount.H = E.of("1e24") + for entry in [["RD", 1234567], ["YD", 765432], ["STN", 654321]]: + world.state.amount[entry[0]] = entry[1] + world.batches.append_batch(world.state, entry[0], entry[1], 0, 0) + if scenario == "hypergiants": + world.state.amount.HG = E.of("1e20") + world.batches.append_batch(world.state, "HG", E.of("1e20"), 0, 0) + var start_year = E.subtract(world.catalog.entities.HG.lifespan, 1000) + world.state.time = {"datetime": start_year, "year": start_year} + stage.stage_page_scroller.scroll_horizontal = page * stage.PAGE_WIDTH + for item in stage.owniverse_items.values(): item.visible = true + if page == 2: stage._control_page(stage.owniverse_items.HG) + stage._set_item_description(stage.owniverse_items.HG if page == 2 else stage.owniverse_items.H) + stage._refresh_universe_ui() + for warmup in 30: await process_frame + stage.measuring = true + for frame in 600: await process_frame + stage.measuring = false + var label: String = "%s page %d" % [scenario, page] + report(label + " Stage CPU", stage.process_samples) + report(label + " frame wall", stage.frame_samples) + print("UI counters: H=", stage.owniverse_items.H.description.text, " HG=", stage.owniverse_items.HG.description.text, " date=", stage.date_time.text) + for entity in world.catalog.entities.values(): entity.free() + world.free() + scene.free() + quit() diff --git a/tests/benchmark_ui_speed6.gd.uid b/tests/benchmark_ui_speed6.gd.uid new file mode 100644 index 0000000..1a240e9 --- /dev/null +++ b/tests/benchmark_ui_speed6.gd.uid @@ -0,0 +1 @@ +uid://b3gmlo2vq6kk4 diff --git a/tests/fixtures/benchmark_ui_stage.gd b/tests/fixtures/benchmark_ui_stage.gd new file mode 100644 index 0000000..bcfe479 --- /dev/null +++ b/tests/fixtures/benchmark_ui_stage.gd @@ -0,0 +1,19 @@ +extends "res://stage/stage.gd" + +var measuring: bool = false +var process_samples: Array = [] +var frame_samples: Array = [] +var previous_frame: int = 0 + +# Exercise the production Stage, with isolated state and no player-save I/O. +func load_data() -> bool: return false +func save_data() -> void: pass +func _notification(_what: int) -> void: pass + +func _process(delta: float) -> void: + if not measuring: return + var started: int = Time.get_ticks_usec() + if previous_frame: frame_samples.append((started - previous_frame) / 1000.0) + previous_frame = started + super._process(delta) + process_samples.append((Time.get_ticks_usec() - started) / 1000.0) diff --git a/tests/fixtures/benchmark_ui_stage.gd.uid b/tests/fixtures/benchmark_ui_stage.gd.uid new file mode 100644 index 0000000..1a71741 --- /dev/null +++ b/tests/fixtures/benchmark_ui_stage.gd.uid @@ -0,0 +1 @@ +uid://d1wm7nav71y3o diff --git a/tests/fixtures/big_integer_oracle.json b/tests/fixtures/big_integer_oracle.json new file mode 100644 index 0000000..dcb5e3a --- /dev/null +++ b/tests/fixtures/big_integer_oracle.json @@ -0,0 +1 @@ +[["1490843018401332546493796370833490360960981158230869717361167115426222336202082454727262516334685086370126336565288574011799846217769409796898152418267582531948674704537820708006", "255", "1490843018401332546493796370833490360960981158230869717361167115426222336202082454727262516334685086370126336565288574011799846217769409796898152418267582531948674704537820708261", "380164969692339799355918074562540042045050195348871777927097614433686695731531025955451941665344697024382215824148586373008960785531199498209028866658233545646912049657144280541530", "5846443209416990378407044591503883768474435914630861636710459276181264063537578253832402024841902299490691515942308133379607240069683959987835891836343460909602645900148316501", "251"], ["298", "1007217418042896563534335530615413723932697742510879", "1007217418042896563534335530615413723932697742511177", "300150790576783175933231988123393289731943927268241942", "0", "298"], ["575220327098424527695236577899249485109905998629984001527909954084290727247251483417641315088738523350294952034031301337107312285090154223736812578356679281081837578699374900537931561196346792541150701606468", "376808572221043619346034393397605006493068360286063052667347893605699273081771717867624345780633978046804728153489736699587917360521766616", "575220327098424527695236577899249485109905998629984001527909954084291104055823704461260661123131920955301445102391587400159979632983759923009894350074546905427618212677421705266085050933046380458511223373084", "216747950166479032753862089877979045184271334605787202328728270707792369489117743303780894774084338824313693866859716018161149740649509691098629624355042545025210155356149172108219098170545620968544391001979591914544619148038889335068278672691859013925525669908777812584155913992361468669354102352497219726543871000165424726404667807712572072288", "1526558495492476515922102320362332994809163253702427830343236769576305", "295364548262955669591195991168753945919964193708750505652866165055343370780635598929698449063326866025300533754426432509470637750287972588"], ["36675501063279023009429033474260304347110678172206450761376495557094640824111927813675492299817451591677776814493368551503783467776599846886265913460903231", "7164401892385236629796908215822982781291857562765666382507128102618999436933690190226652876775276874067825297682704162", "36675501063279023009429033474260304354275080064591687391173403772917623605403785376441158682324579694296776251427058741730436344551876720954091211143607393", "262758029221932990598395435890039327979005634269503105578807888608849713285005193682780083232804317944601961464056069010769236004727809143556930690554684495110667216978137104056730340868755413174934690469458988721480346735994426990729738247659046625458433289325067082947422", "5119129498061796728432577510972563110", "4972859995893716895566874407508913311684543564981124486017156927271291346050635751457942206231942451970702740456239411"], ["781816353409483990564499756238395695393795790446369767422720044728367101926810614360867595490129328589479631732658025297011331282185441554408735531395732371905402478403593117144941702200505417555032957645", "77364419724843289073926414580097017512873581234860863398627916732535910131990713293849", "781816353409483990564499756238395695393795790446369767422720044728367101926810614360867595490129328589479631732658025374375751007028730628335150111492749884778983713264456515772858434736415549545746251494", "60484768512917735076937625048291238286254689624613093605848856479816750475111277263038580385533875127818679673632568796614452955858797678083961482623923205707215875457793082273313330343192677998146554367476995139757779685103582594544779384237397806286802857751013801839365211191230456025605", "10105631971261678761454382594445395616629873938772793992105766987568378665539162885464161860055788459697883192536477122", "14010038437773039109204128753548278679832993294269251485964962676380313332935781135067"], ["5982824450660973558420088648657970024180805116106954992003236304304765219987771154", "87011118697687618112992083631663718068672882235584045335949642372237617398679679398714959127509131", "87011118697687624095816534292637276488761530893554069516754758479192609401915983703480179115280285", "520572248423889688856395195196581930275960809982950719297441769857181355258235844980439894746017236544820890558520449222706820087089604044893312606019604143781894528157216473407174", "0", "5982824450660973558420088648657970024180805116106954992003236304304765219987771154"], ["842653095343987935139739696257344477015998594830704142750794619008", "695149700546475020462017176364746175586585489807900763289", "842653096039137635686214716719361653380744770417289632558695382297", "585770046892933477436497425432474637545606253719973982348000626319888474808346706540593640519828287791077763719837147997312", "1212189395", "404125210703274474760154511103131759824686250279463498853"], ["649772175100959877477082707721034639210200095184755811665539211725176129842837892449492725464990588276579623519752682564741352885237376892117510028925686535436617873686823848117819", "130823476531448154481198209830718145756517620", "649772175100959877477082707721034639210200095184755811665539211725176129842837892449492725464990588276579623519752682564741352885237377022940986560373841016634827704404969604635439", "85005454900108445398725168133213395828429991172940669258808702030858435523589207903734876046984802426783333339736645758555566806235472142095170864795336490654606100624100493848030510138098644426426956487383944063088909470780", "4966785720181986089276493917322735463736732338122598013009482735129865363565570934620725998677740936994064493298246210960062822863153321", "113879837356755391395967571399062942750101799"], ["909175504115576232729234906968484708904648873084715932258266329229015368351235636405016997587672887554266498150422751207533093652445337083806504304836576264733590248950015596149512809011567783063191094154355", "75382149806912415978283205167949797087625612787472688372842847726247105166657929381640009056570900321008", "909175504115576232729234906968484708904648873084715932258266329229015368351235636405016997587672887554341880300229663623511376857613286880894129917624048953106433096676262701316170738393207792119761994475363", "68535604052015483370627045707620881324544768987768951101567104326691251679740031343124528978383797700395300826439484602027490831939891604590694835704819327254902220363106984327234643036441779134364207141151646866889382785510078041244516024160552072650087144112973308451536263705415066657717563040448021801189840", "12060885852212805592500484215843859439178977422728969350442416639890303502438660752794529459315735856212", "68577325446271645598524943029810151575219671111391195271523158773676133699584331570307650854024563252659"], ["261869390328609489928625005297847739769047471054867206747707659659971430652099368979", "4600393313908359716528296987048993672256140677298890010828685251087843632686707190247768567693233917079316742754200", "4600393313908359716528296987049255541646469286788818635833983098827612680157762057454516275352893888509968842123179", "1204702192384993575222320994514240261921116322448205807978331046947780781287419471212659957403233568160864573024319516230724057660569081676259518547070530062387113044374671531494371148483490501961800", "0", "261869390328609489928625005297847739769047471054867206747707659659971430652099368979"], ["98222353589532097891061663789078179451070541736489317520285186320578731163640572201047723143947574281769923285512496269509143597665111111384368856", "697807660148849621887127825491784", "98222353589532097891061663789078179451070541736489317520285186320578731163640572201047723143947574281769923285513194077169292447286998239209860640", "68540310732624353916918299817349540609904404142077838811804252197898930719644286650733641975694659990178320215166214178068117768250517307754891908648298823199690461022068653479104", "140758491485433464080993881851237839213652188977224982187167082483138489458554785311232215942704582319040318579591", "259482767040692647533859463788512"], ["50952857500547928350", "32802149044969586945359007997298880968480602186620096442038871360878246", "32802149044969586945359007997298880968480602186620147394896371908806596", "1671363226000069682863402082402882368306050895034948159010584763431987572708573271881674100", "0", "50952857500547928350"], ["58915577275054457291026771435723859685884035183", "95244911565130561722441331", "58915577275054457291122016347288990247606476514", "5611408947371177584490570761665056066659948265351758436839831952257348573", "618569289497073993310", "68371507942856443522539573"], ["6013281089589958960048941755098580742228025691342701618665659334370694204725985535842940700177952172167830734959579241333689656181961798562175959807179409646475842871433331964978057374097800322154665320404472890", "611317356023901497884612149317502534599973763593520840601198939818668227293744119546408170011911580710731349178274932122431056994", "6013281089589958960048941755098580742228025691342701618665659334370694204725985536454258056201853670052442884277081775933663419775482639163374899625847636940219962417841501976889638084829149500429597442835529884", "3676023096716659260848041348751063911581621065838479812632573443702745760012750861641065706718804929303686824458296699961142377059144845184265148087835460678727678922412888130016700711172427698339658025421421399206350524174365300004469877686486225949549196617707927989502675110122435096936391009289149110925266793243617686028771528117892660", "9836594741397869965997879461722136263699953207573853515941538644058450847875680951", "47884595294633231895902440682196039179480389362049522214790639649682137175989125349784762282450636543111860105319214981963351596"], ["671153883550598360183561010616696113370635819927134548294951631234", "8354882239578078988149553231323778654378429582336289577397718824214520136519409552639067", "8354882239578078988150224385207329252738613143346906273511089460034447271067704504270301", "5607411661700748455215731646224192275759835845180873587819100706082770236639325611057477761314249838703445208563784925586737490768716812840131001285818678", "0", "671153883550598360183561010616696113370635819927134548294951631234"], ["149941206482700372678073403309175086237298565549472242998900142273271225943464949012733805696030223494627290200962825731261148129857686507200805482056853157", "12713747694406516661358340195383826067398469", "149941206482700372678073403309175086237298565549472242998900142273271225943464949012733805696030223494627290200975539478955554646519044847396189308124251626", "1906314668215963312688185206676400208815128187022221990893075488459437469445434647037986481169429275557020036870666825011881542291067603350550276346035809450918402372082385370613464392277555739616633", "11793627660919197924744750714707068176181586802880978495244907165208560510558194821317561437131515391130487714476", "1887269322998304551312754753289127065315913"], ["159682409333528666724844875295767977804602045333873597699645974539441817560208831322019601566216229391297119322106206878", "327122808190697527", "159682409333528666724844875295767977804602045333873597699645974539441817560208831322019601566216229391624242130296904405", "52235758159840346572833053899196558593449443325288528060882116209154090233095740537574402032051129557856006127143514845109843506984990706", "488142084059272254932818792813633107710168713788430769484656128251414464066563217971935581177226134160", "88425538023984558"], ["890885683581096503488119895683801971748539670465259883196865898979002541603966147439707306759621486446463756482705404037009019605995281767910973198872603599758944327205030917991630878143174139", "247280334149155984532688795062475684205776361898", "890885683581096503488119895683801971748539670465259883196865898979002541603966147439707306759621486446463756482705404037009019605995281767910973446152937748914928859893825980467315083919536037", "220298509524632790709390366938689939167191962089282714864645157919910717523459788121894454347099949026353823369181248820965665540188819686633806788415518707401274867023825179134399396378745931850565518428828659993512954181157415885298555822", "3602735683152736746369908631710370087910614910655286497251771807709225618999786686771865116665666443329665932002992906129013044368389590251652504", "183748033355310471087748161445198916322501281547"], ["90603", "94987423267254578978594929941150683014101939980303011135966285635912048144084899600166431", "94987423267254578978594929941150683014101939980303011135966285635912048144084899600257034", "8606145510283066619197636437458075333126678068035393717951953377470539297998524158473879147893", "0", "90603"], ["7671226174827078645849752940153731", "631863759516323474682070078226740", "8303089934343402120531823018380471", "4847169810926263241814017074842519619003884660312851616811474966940", "12", "88861060631196949664912001432851"], ["495630817581553094382816930950731822219155770256434168089922438848973005262895274643963422315358", "407571373109522849086217617960991074", "495630817581553094382816930950731822219155770256434168089922846420346114785744360861581383306432", "202004932877109033386466377376747973711671004281483130043327483719010461008820738297754311159762814935262616651764166089437451114492", "1216058953797932351608174166826830177887949347215106011520779", "307172879944929984528245110637788712"], ["85660586474795121487026531118039343187825333940071276848203", "3861828932951804929210019465629169598520926535098322559890097403155267081", "3861828932951890589796494260750656625052044574441510385224037474432115284", "330806531261983857376785042016666048709671985165798911828962414001529992359693678423447515591534176566313849007681611604972359905443", "0", "85660586474795121487026531118039343187825333940071276848203"], ["56427971943929562876659884857764569905860972643339915849022887247275262640986728793504770476320269606048442962592739653400861544573008303714817525815337933296509360784350967994378722341", "16680575846889047", "56427971943929562876659884857764569905860972643339915849022887247275262640986728793504770476320269606048442962592739653400861544573008303714817525815337933296509360784367648570225611388", "941251065896844252018585898602374670979424051689658553224527177883907426161077728344669724366760839828520699920181684668049010246631850448120816606805554763346861943195806129190997654700123595447099027", "3382855152117153453110804909302935592051018312550511103698307718606658542493259847875683781015789793111420506915059087342586278729621262762794186273313867366637342823520", "14985571236736901"], ["252227017918705183295238630699107756891927523171357848757114484929433275818509660852903952265879445173", "599084638100919259137282556236880436060396970600337696431732669566400089218237442329782048763102161913932", "599336865118837964320577794867579543817288898123509054280489784051329522494055951990634952715368041359105", "151105331749101571945913501305490612062936318140631507170359359206874239227858975729699388470635253855590008420084521256331260052417221195133221638474781196566235947250125149061011878405320383257051938850236", "0", "252227017918705183295238630699107756891927523171357848757114484929433275818509660852903952265879445173"], ["7266897977147742197674745496631475811351694861484130995552740001444380419903573769182808853337873872526503069993719592098649834657463923859763063167555016914907856504423394337462115073661266", "5829433945576174498996782681765265975739968676110317376595834075154885156110758031323095660518516178601457147203930724578700179881265885021", "7266897977147742197674745496631475811351694861484136824986685577618879416686255534448784593306549982843879665827794746983805945415495246955423581683733618372055060435147973037641996339546287", "42361901747023883948477895353653984475919223935078335737380147526705144599944004029599236014687723840406902654662999610766147314948123003545769080990216281372473095499564466280710733003150767107289892070526782801995000871989932265351138074810546569251443649637248950126622125724182997368527148224823717083387595015254188257296586", "1246587240715271612671106806994194152567066304440743", "2304921700531388915358555255599379773315306019831233751689368477369240347553989071400703241492222310545441411198861046139503905912727850663"], ["1429758269530322273059901376414570595676826526483253607820041784442701801791057840648523524290041670523364107743560930164464721370720162579507602340365903332254281133", "86", "1429758269530322273059901376414570595676826526483253607820041784442701801791057840648523524290041670523364107743560930164464721370720162579507602340365903332254281219", "122959211179607715483151518371653071228207081277559810272523593462072354954030974295773023088943583665009313265946239994143966037881933981837653801271467686573868177438", "16625096157329328756510481121099658089265424726549460556046997493519788392919277216843296794070251982829815206320475932144938620589769332319855841167045387584352106", "17"], ["979005441044863755709909190814126654600146276575038643076308530377029682806274571370001313543199511869059035973018779126562423321340589837963994000330", "346", "979005441044863755709909190814126654600146276575038643076308530377029682806274571370001313543199511869059035973018779126562423321340589837963994000676", "338735882601522859475628580021687822491650611694963370504402751510452270250971001694020454485947031106694426446664497577790598469183844083935541924114180", "2829495494349317213034419626630423857225856290679302436636729856581010643948770437485552929315605525633118601078088957013186194570348525543248537573", "72"], ["808532365355506056890152518407725825082023316510755920377054706852943384034120810888216918977652108633268617633255275198027181976097240605200", "519251549194368409873141690471110036738223743505232684635993389917498237515464271", "808532365355506056890152518407725825082023316510755920377055226104492578402530684029907390087688846857012122865939911191417099474334756069471", "419831683284633605904213565984176802676375856119630274849393494733436321809526094735293459761989544267305568042945677604468962206379716692816980027611814112560570765568107203002757459300222530852415414129116586071016809200", "1557111127756795277258363728227142885828575665505708529741976", "231900722751758537612550035726046100442227705501633812387538998243457855763665704"], ["190594795510133066904933721674434033410995118824779255247286394402729212607597781854545924277970202502634338202544347081051078935223885643856739559019636910843049208960361010384706564151114401028988907538342011962713", "62665113885148718142773915077583483257266251101738", "190594795510133066904933721674434033410995118824779255247286394402729212607597781854545924277970202502634338202544347081051078935223885643856739559019636910843049209023026124269855282293888316106572390795608263064451", "11943644566559120213112637254942397789196696516245106072496220729440456995907916973089631020929805059511246213842540819595570312809206244991108799428380006986651391925073047370477299580139273007824744354979951353124632018782396672461493859552102317959164912025495194", "3041481674468048298178337159932506950344015390480661875668209435847861712276973914119392001739612821901952493820040276333213687615740231644225989149134099101294149764", "34533472248561129218265138707220763154063039272881"], ["910758998469498", "97168579191678455968802116745222968881824291123415045744", "97168579191678455968802116745222968881825201882413515242", "88497157867317174089667986827598948633044165239700522433790721658716512", "0", "910758998469498"], ["29852834314358447354112299323341585", "352609730944170508144813151121028824011056683276224", "352609730944170537997647465479476178123356006617809", "10526399875506832988903482193462349261069867971489018930640318984807658174353260975040", "0", "29852834314358447354112299323341585"], ["1424566039486638295114348829", "45792937135242432919431911773043874278691003041488531518377", "45792937135242432919431911773045298844730489679783645867206", "65235063091212916824531255390172383703681412703405695350402307689489396443271001930533", "0", "1424566039486638295114348829"], ["26295782015744951280480577928114", "46644380409207408453831919168373168291628120565890095740893145333012724303864167363977726096944706918", "46644380409207408453831919168373168291628120565890095740893145333012750599646183108929006577522635032", "1226550459500002302538094580309023972504541007019225282883140705359453333906150145967090112796113938087064995803103630196271402492652", "0", "26295782015744951280480577928114"], ["2864021138069338876095174695219841910258691952728385694761597905221849146033897967463942643489397276991796561881111139016441948816", "48968323628908930066002853486810592143686766480119962", "2864021138069338876095174695219841910258691952728385694761597905221849146033946935787571552419463279845283372473254825782922068778", "140246313969015452110689239148489774185937092846972478010357504263622058064216465205277972742260289196304782565555223709986373028739787805524881151944950538689352106459394896743864992", "58487220427912216929349138043806489890696021863506855626374522726530941696352", "40893317576578732783565774039740983566142307704170192"], ["11982797984221845147288593116843806445739538453062613994958962283387497137004009326365952", "97140630680576348398388393215882254349601807759113298531807863983083412792284430445903903", "109123428664798193545676986332726060795341346212175912526766826266470909929288439772269855", "1164016553505248993067329354511717461229521781282107600791612728770375614429187320832279780124724209670465808179540544703594417261578393322360680634368124434169737002338803110656", "0", "11982797984221845147288593116843806445739538453062613994958962283387497137004009326365952"], ["968187203778148485038167400437135874286214321190022950085221547620680537628723123849607569329454978945540377518492326475044870244831607670255481631399610352402321933812768810883586969336161311717", "2780933837031243039123872684304864736475", "968187203778148485038167400437135874286214321190022950085221547620680537628723123849607569329454978945540377518492326475044870244831607670255481631399610355183255770844011850007459653641026048192", "2692464555567316473939801548653418454880001682187976398769576229143346652798642934376731210808243235349488480349574168465125355739584996227646665418148877651325403232469307211100195386891905737192551845060485241211758162412693534777575", "348151829750731018128935603749982533001138596517423146498385884597108948398361455944086417697184929224831594405250874981280774177785556766116670087209841619", "1881718604518019682081407940133238958692"], ["23785999747058567206398983379", "2140647271229821221780976763844355813164497813827055055382796874", "2140647271229821221780976763844355836950497560885622261781780253", "50917435452014139690699081688576347828950092515078393416853900235517167898991374479259157246", "0", "23785999747058567206398983379"], ["26716489867753661649058522965637019962339892117026241168438315882101821307633634574646116", "6133046367641", "26716489867753661649058522965637019962339892117026241168438315882101821307639767621013757", "163853471139544175032935700361832704341708481963359598088770268873291935975292919353232111806808732356", "4356153250155489557496256600416130439711895382963915594339488545094544065139", "5876528879017"], ["6618496722204500094931708822008937774932071564748139249121035142860684746125307490504803135", "2661617443397091298972271051246115679702497247102791925957941645087543981934890208434322", "6621158339647897186230681093060183890611774061995242041046993084505772290107242380713237457", "17615906324885970326429295224360266724773352840134756436636514297345957807729355332833036810672675933561250391344030806699814230925259482480543115756021475227809662770229187199470", "2486", "1715757919331125686642988611094195191663408450598521189592213173050407035170432337078643"], ["61098095842743437683392696752011693168833506679855005340530280068", "7286763749852275913876437977805004715246007", "61098095842743437683399983515761545444747383117832810345245526075", "445207389971902921889470801368431388067839020245793423539492612550764487343731456147309488789818353228688476", "8384805373164743456169", "5407840368437507270086380324425460273512885"], ["97474775358417251302121368814967872062173265244220699578166855", "9430846074993701419668465906135472685196133243232964686474644233", "9528320850352118670970587274950440557258306508477185386052811088", "919269602599822099952006719208459422749733852079338282017096626449833543464088099380569365810657218653137430464684960437497215", "0", "97474775358417251302121368814967872062173265244220699578166855"], ["365835307651040444044686486155291284998383398656888801262442274216545361721595415056862960675979071091138251621345452238056925396878240774442684767913119", "1538300756546837972905149346233264546143734137733964573", "365835307651040444044686486155291284998383398656888801262442274216545361721595415056862960675979072629439008168183425143206271630142786918176822501877692", "562764730531140737313543549096428413727361070113615537296364286232062652286029481712310909098329379027258459696864657614812852567550654814304948147231415663754070216035472743483867545063025889098259487933187", "237817803894385291612199208582989279537045091388460465102229342496420855519947600722867133777647692", "1173157414417025994701768322188423000695935815564697603"], ["233", "97337203046859697929013335912078424788057", "97337203046859697929013335912078424788290", "22679568309918309617460107267514272975617281", "0", "233"], ["9588702732781807913325447492597763468534130905767556286903160718668595830307736245143947236495283494181647330037061", "42607333131184675696958436976535609144244038762086489732090175677477336256702308936156482935552055477262958697739707916257108250748", "42607333131184685285661169758343522469691531359849958266221081445033623159863027604752313243288300621210195193023202097904438287809", "408549051631535364459613064985399378288958950581000220170466852409603229250200702447272766219626381195434690840472498560926218842614710025794210658656800051906707783137001266262777188977159667217358638601637481998786999559596175865749391720971628", "0", "9588702732781807913325447492597763468534130905767556286903160718668595830307736245143947236495283494181647330037061"], ["282873502657600316769600770175496511313325142", "1108586326865941339097358170179731703284343794988641953938612598865382617104873219553457887764058852134368426595590071042293731175294875628", "1108586326865941339097358170179731703284343794988641953938612598865382617104873219553457887764341725637026026912359671812469227686608200770", "313589697278892230830530429736991738002624766698306207633187775090156264489773061654757079594649623448846071098960591566377626368672006013187384738377958549915984955102027706015439176", "0", "282873502657600316769600770175496511313325142"], ["606489183174874943214895633723411348530670505640774628989405755397070861126625202278016132604035225357415956025976641776966446200747430467077332276012682149", "5509264868031035171262236973523327482459468020504316982338658164827310", "606489183174874943214895633723411348530670505640774628989405755397070861126625202278021641868903256392587218262950165104448905668767934784059670934177509459", "3341309549706177720615845943795689939444313448762233776432434708810343998419040513444671819969897723317236161940509626137337148262110744320312983318255793655976691166199853005593837919707460789978710329439098260563966504689190", "110085319494110484736806420744268992608077364103342131270730420718457137295460382710953", "3044084296151351184629669163832415722177074571322163695317385122155719"], ["68281685372863213186602208440444019707142680258474865761162062289208464364367875673846841949786936676", "3962140899181321441126338661595263330370096024203017236", "68281685372863213186602208440444019707142680262437006660343383730334803025963139004216937973989953912", "270541658280852335293535525757967578058322182566057995179820886455270420119327971922988071953979734316484115277136019103226995549323467330901970896868547536", "17233532857696185673468304045319581034947724143", "832833677376075271550416820815941652280628157784607928"], ["951491941646521074188270161563333078805738890862809814228762243876811040959835999708832881194998254077347224657727100706323932489849167527564068484028756063704222155986", "340639277986326220677598805371050867115059896275", "951491941646521074188270161563333078805738890862809814228762243876811040959835999708832881194998254077347224657727100706664571767835493748241667289399806930819282052261", "324115528012278579086159219949927368746344348169863454043845884508720554324519071026714594549585844850048871898899691404973335471001132080848258697964535653079116101557005308841272072828941226076299633409306030352150", "2793253752976529646114210490408201662395709357515332248946347929152926144388759973856691728830701967250115648007789316444", "131172054704121902549017002614549973604430309886"], ["2042787019399452160228655336186933732084572447469416139713269189827780683270800514195762205369958541609039373582343273362397", "14837424842277832439961003993049918947928103189740260177408666458599730588809859203461789579866143335508914018966442078619098", "16880211861677284600189659329236852680012675637209676317121935648427511272080659717657551785236101877117953392548785351981495", "30309698869120119905287631676929433988824408379724405144687992774389093098465060436097587316382974735189281568168654895930312711920315946812296066991972905541466413901429786201642734727822976720895375002865819242399639257936022704904559593079257906", "0", "2042787019399452160228655336186933732084572447469416139713269189827780683270800514195762205369958541609039373582343273362397"], ["4484879117834948640660143782750976934699976338", "610306968063582841628590290748284204146999626449172364534309157557279979714908366350295103225281679151399927414", "610306968063582841628590290748284204146999626449172364534309157561764858832743314990955247008032656086099903752", "2737152976537523587989685142807838228782758331340041614285269108212040374053140284367076474701124548064035658152209211517511253908058137836076137440717529932", "0", "4484879117834948640660143782750976934699976338"], ["9938750531228230371910769866691137483014231221217647107370904534304434525840418375974729871580275154048284599303039043599036505719479449008846559106216622555088713794993153036598794371580087904798605520350099364131778", "20280003175578426020135467085586068784802716193990258979353486883653006046519072251207003815220362945297338", "9938750531228230371910769866691137483014231221217647107370904534304434525840418375974729871580275154048284599323319046774614931739614916094432627891019338749078972774346639920251800418099160156005609335570462309429116", "201557892334590280506879448287690542593501699833981039369964045293541311666916714038332666159434274958900162800575014931942050655122335616287825094639098258614044446147714750366242684421820020460840092449992296869165986501783152534993109722688548340475558469743726369055046020151625904053049892891243303865633812898424606964", "490076379435515420829882863977173985489233199506395651474868840050169175865610845850864988993820401617540830817", "8612585386898160855755811620942476259121971740320061611434450092073242637651261341441406952612867745666632"], ["9550494176875531531208998875331501593688087183736418562253925202080030", "819934641432416553150784946232837025547372614060280292267067483141882051316664561593688949697621", "819934641432416553150784955783331202422904145269279167598569076829969235053083123847614151777651", "7830781018418821220577191194539745858769142012745394388040168399012579471212129043569020209889287755820199457984267446489360378087705815639046964982481177988742608630", "0", "9550494176875531531208998875331501593688087183736418562253925202080030"], ["41010984473688296438624479962148765020272289034190144278", "29106381244635572376716437570615917146337865130241669546741815933170714659", "29106381244635572417727422044304213584962345092390434567014104967360858937", "1193681349309001691836914550865325883588592279780315927989804130146283195130636341180449986350580348116989100474610391195579571202", "0", "41010984473688296438624479962148765020272289034190144278"], ["119876466704403095900411", "79393546423613078183372111034548226288256760752", "79393546423613078183372230911014930691352661163", "9517417824394734659310404517457413163592206172494289840818885645469072", "0", "119876466704403095900411"], ["70490061309919756010846669766021488160394169027686235354659422326311773433906939056110749202850397131950881847803391195807861675990012543919149161360604277074028070947", "303477166674282637355448357331249725723677350080435601859643562132422410935623", "70490061309919756010846669766021488160394169027686235354659422326311773433906939056110749506327563806233519203251748527057587399667362624354751021004166409496439006570", "21392124085030919688983156443310435965572560568586190513683198785318927861035420496160883576001484322046346687037652807847970601437010841525406476981772307498651026493014958465643367519781823612673197485307630519961205970010994305286088093644981", "232274678462303069043409342926210577177134156189381995069339197266962937160717102796990529", "286813555369429678221993340951041280714579138345762738695819461809490468356380"], ["3709101339799", "83224781464307589963494248632588428455594160266635045538423980139949542588847898227", "83224781464307589963494248632588428455594160266635045538423980139949546297949238026", "308689148433742263031441243102764563677988156221576378483935762071997015940552950309590896636373", "0", "3709101339799"], ["5965773464650532870988", "49614382135105506609162772612901918868", "49614382135105512574936237263434789856", "295988164406643880621865810627463078912276622403254287001584", "0", "5965773464650532870988"], ["6388012408972290960994180231001032121810903847858107719323916276519624413086489967029", "8935404293746011316633585346501042230952439479409282639776957006302363792256983392580768591228544358659140542399773684", "8935404293746011316633585346501048618964848451700243633957188007334485603160831250688487915144820878283553628889740713", "57079473507633809918801593627040193632807827217124101506008643064516027141782378845542551896168067390750112556247332340393981436630008379007057157065576532607012637835774542577157812042981094466221864836", "0", "6388012408972290960994180231001032121810903847858107719323916276519624413086489967029"], ["1418489545822906802807278113586360467757748659228549790677031690215167355825460439749599436020233686334864585565669690096622940957052452176553884973382037150111667015188275328200451882", "31209257585218677689853011107484707514113811472329155142407012898688890180542804165561176105677034139178967", "1418489545822906802807278113586360467757748659228549790677031690215167355825491649007184654697923539345972070273183803908095270112194859189452573863562579954277228191293952362339630849", "44270005617526951219222343960987763770544727730225617973130898744207526769021354357531937951601238217016253961466622935275564711650447026321251752174545825055978905413972253164242605402857209942307386226687616647224266776362536119528303078678286699049727460905543396811015040002849869965894", "45450922437024953026836351356895314716444450079467122266194557429247513129469", "12538724125559311236330166338821405446625175067737720293142889512125806377393746584208048001895703767773359"], ["396560866745603379625193660879935869220659998017832549752089697417223519369682768241337759161157480344102966150114421643391517710619945843569818659606633553135145355270693136379019660274", "56203146883282013306216780", "396560866745603379625193660879935869220659998017832549752089697417223519369682768241337759161157480344102966150114421643391517710619945843569818659606633553135201558417576418392325877054", "22287968641864772380683088344501512491259175672151186114287719578811541229288905071226458658720544033896831396660284080557522217494221304521443754637740079849995980228713679597209062232341719087479111487798197720", "7055848092797148235020485935896898543949871673293630982126779846735389532862027810322783155209017212330024882686391704830724032158832902323019404799927348123607", "22767927032579138042134814"], ["64301472024266474179532913967427368450816768436394205458772164899534387279753128088494932738608526859306034574038549714776002246405383606981586778377124197442800120581568028593648420345355249142702031080998435", "8619044890210921925633968711284174691994578956510721412245166051452699835694113120610784323103807139419898208937140080377982697829863701", "64301472024266474179532913967427368450816768436394205458772164899534387288372172978705854664242495570590209266033128671286723658650549658434286614071237318053584443685375168013546629282495329520684728910862136", "554217273883794500575877157517573992670435876968977671476790681600419255918586553522935078366795290718436907661654562518235037586701355652641889553388538356786304796926938624355967855626885542701689497019276246915603203850087953513020166101771529034339184332236943505176911786252525992258402040142658323636675225379496644488198567173587044307935", "7460394143821765555363019330853121686071716562015608593433404766578532800", "546570304464610202383878006894683790766502771589734676277074944858674096302877951730415973134993847161034675192672382471838094523105635"], ["9694756706979415538379774018710337326118193471101841520260123303133138863130437314624640719662404320232515959483355717885173827938950820073787527047214018883689267135670431020568461158188524403093537143410630831271", "82700263306", "9694756706979415538379774018710337326118193471101841520260123303133138863130437314624640719662404320232515959483355717885173827938950820073787527047214018883689267135670431020568461158188524403093537143493331094577", "801758932354807152945995059972122667414054590937172395666995530781137038755148661342385352071730168712261012992120745593564529044131172113486858835503196055415558580806117070239522039581424686123442002706950252625673358641926", "117227640147985474400440768273922686730728429866044585387237283328089659941407941744439319931352242752102610330755017752170127872203885145799338902134039341938649318472466521273260106180931152682411716424", "46426093527"], ["39163884259848590067199551882210423881012048960096686967863684099057419095024358863423520898907748356071575175545537408504549305283734312592736354", "24442552750326488650088151468960891448179778", "39163884259848590067199551882210423881012048960096686967863684099057419095024358863423520898907748356096017728295863897154637456752695204040916132", "957265306929030433434857660960453451421069554303841167299124294721677468507866313562699875784498821292427181585755184052628698272646447943510704860409224848968015075221885928726597548249412", "1602282898185643186827594764936956340028206323033158174275833275834336198127007674672100649385567183575", "19054258709077535582748695311832248863990004"], ["84659331038246931316745604776974246799134504051276104888698773940550670385421269610094119949806458975516816706427459400483123469545258690220916741236772908287558471479618536071413", "8501065232039239", "84659331038246931316745604776974246799134504051276104888698773940550670385421269610094119949806458975516816706427459400483123469545258690220916741236772908287558479980683768110652", "719694495656941397538087811496286664409353312552017679306170399946770590138450062510922864551167756698510805378067530410282152009129966783704380113840249402532277712210744240481815675149722174707", "9958673263578618183288402671332447571873201000865272780984798529763547152123756081229884142704703286488229932237855311892052337678371369606113749094543897847228948", "6085255183380841"], ["3557921349570342438041614937743450121285512868419792370799033", "411662151784913985195115", "3557921349570342438041614937743450121697175020204706355994148", "1464661558645612319352834777764476704507833153476630197071302239458177414604958323795", "8642818714675746708097419995082603806", "317371102535623219191343"], ["3242414206677332468106474029277084006441233557830613613646324658713721189909497359824464374584625628199554432809225824380734196953718278123148527606528224678270723337871303712672868380379553234355529497664945", "47", "3242414206677332468106474029277084006441233557830613613646324658713721189909497359824464374584625628199554432809225824380734196953718278123148527606528224678270723337871303712672868380379553234355529497664992", "152393467713834626001004279376022948302737977218038839841377258959544895925746375911749825605477404525379058342033613745894507256824759071787980797506826559878723996879951274495624813877839002014709886390252415", "68987536312283669534180298495257106520026245911289651354177120398164280636372284251584348395417566557437328357643102646398599935185495279215926119287834567622781347614283057716444008093181983709692116971594", "27"], ["65431929349613985965089626325213882055360870564251076038039143781070185266625971154562279060369250443632908703043779255993019708758719169417770530422163495918446861368189254570939356198535224462882275", "1252507647204144758527846755036066460492726987352746879258690605304094600425918842635", "65431929349613985965089626325213882055360870564251076038039143781070185266625971154562279060369250443632908703043780508500666912903477697264525566488623988645434214115068513261544660293135650381724910", "81953991881712839336513508153904415488505643782024131617369446767837422641222624186899224685644003530047728061384475615070247318522709884927751210468177600677808036052198186846834983072775826428971835874590203988522055481136238099064496604346611240732504529328911348725758084255794625", "52240742398396959426191378055154766982273360499824106228702587398049659755814240311225219277343196632230768106369878", "1065161297513712568321459237611368822903235630440176231238684485363637606215476733745"], ["20513122174733190604062600114178729158236890899693847745471143078883461605493957119210521918992514441623283076747592763902913798091378742415007237098365", "576887853890266", "20513122174733190604062600114178729158236890899693847745471143078883461605493957119210521918992514441623283076747592763902913798091378742991895090988631", "11833771027970656401428465123782516675613217749306546096900581261202502467066605756652106273548106086033339470842346744090060260973802435893252947483976567602958015090", "35558249383137713871632031289340334212932420543240929425709738081059155050404133555412953989081904876889983588574978427283026972571439204", "136133330710101"], ["4774749329525871208558296782695899295036954921774781533848539140500681102827081736642571194936204923761767711172916634886554129111233300481690765", "2411426777071449", "4774749329525871208558296782695899295036954921774781533848539140500681102827081736642571194936204923761767711172916634886554129113644727258762214", "11513958387022633611416122399286123554974375611640743946253385511547851871144748464623450420599426429225367133174227791749762704844752598246504617040730728468485", "1980051550777151590577539679821148748259675506149683921590479367056876196631134526573880399498868027663928146495968279922423574995", "45417356873010"], ["4572064094477217822078243", "585792738448278", "4572064095063010560526521", "2678281946264855854761669068044924615554", "7804917668", "376149955702539"], ["57896482289173142747752285452143839804629861160502729068048875223319780631007609758762759240998888614850692348001296939968016846936713933459984808139833733480", "4903160157914", "57896482289173142747752285452143839804629861160502729068048875223319780631007609758762759240998888614850692348001296939968016846936713933459984813042993891394", "283875725243647290807556759806087994466311268956050456356922481091842697614051110429710898045358473483889817418558270546450386461335630657147903200278948161243500988760720", "11807993299122543198695330924010098032799101071363260118941869488397972377024245550493161018694445930529690582060495346769625028993169120533018769", "878667845614"], ["88322090943269079104767195125205523631439363891313194418815737810137797525422941840396205627914914611518763618622141778325679972935106", "3034054079773449526424191047", "88322090943269079104767195125205523631439363891313194418815737810137797525422941840396205627914914611518766652676221551775206397126153", "267974000360547186465258379069511954365416236752336912051809135279092128170108944703516061524061182654222301576859491539150426043411997228622136659166030277195982", "29110255987877454506260435783523181165886673867310805958412667823711336699237867766212926787672993333855131", "2636924028217795745407722949"], ["7229461552801518258045761574574286573081023332268297691695339869215734954188751484081731119429845164431942214346809299215906352924073062986536806460797027505196082", "869208245490167772420244955155829016269171867585771063615", "7229461552801518258045761574574286573081023332268297691695339869215734954188751484081731119429845164431943083555054789383678773169028218815553075632664613276259697", "6283907592149231583545938856745628325580090193573737735293145432846183153855658099757981429516829640479930352393835191239638798359986089726768045642184122034744597883808085310757188620990902092625772195374212892270756430", "8317295182496397288407989936522644842674523225605674368580849729285568189671442692747540999467566165927144", "164822532353962661815806255957013655288292418314025930522"], ["53800490341291315931354432497428098422646698527978925211867050038364530053749953302849975383518912219252102498867", "730297827488353971409541516669253804635124708762710340140404505610432433013586146059671910789474489806264869622153361677764", "730297827542154461750832832600608237132552807185357038668383430822299483051950676113421864092324465189783781841405464176631", "39290381214053219520588917034504409661677809112230243352137375566284673450428565491955016738579350700872673571451664296009485492437472385632449335916249921465774094858575223737407878385450047892123241892809563293550900778784740029093388", "0", "53800490341291315931354432497428098422646698527978925211867050038364530053749953302849975383518912219252102498867"], ["3157561588912591577566399938046937286357706746956263673560240605671670621869562391882702626184627113068908898", "7251533085573779934219221637792725452494464752948600172423666787604962797000582984768986462363", "3157561588912598829099485511826871505579344539681716168024993554271843045536349996845499626767611882055371261", "22897162331736572478594500685187139666909599313764252791877839109651666286393445587179266315592891427670538820688742006687068148967843624272067186597049108899118645604184885086399086558145489717352805974", "435433659565623", "6567887046824437999358562376533717047024596726402821274145207242445563740831562451807050761749"], ["4240553945741747678951173633472263170844254448840136039365267133716233432789778610259878132152800657251782030756648114618013505774882829921192779724", "6983556034562255383506263255775", "4240553945741747678951173633472263170844254448840136039365267133716233432789778610259878132152800657251782030756648121601569540337138213427456035499", "29614146097671564894086987626595720885257185580367711528601474728993643626259498612842910581551273909048366528247518530115795823639957776160301926532751106491600897626494645906100", "607219864028420430001987305079907972546537938087554043236166798595565392589293314125943479898826470146294326705876643", "2064946037124634920810485416399"], ["93679673368637", "558424195509366222165059186590351695131464067787703940071301048266609934124973267672529552871323278539562", "558424195509366222165059186590351695131464067787703940071301048266609934124973267672529552965002951908199", "52312996236461316289654332665691055122018723719779458083746896242237439977237323135331810070820052592700085154214516994", "0", "93679673368637"], ["4326430258054263611118743944961586474451416602271796471270806693610297799565029211208460207603943505575212969966747521057929478395251757512469295113920557065633979102091665584830268544039662426961572991498572", "96840294643290", "4326430258054263611118743944961586474451416602271796471270806693610297799565029211208460207603943505575212969966747521057929478395251757512469295113920557065633979102091665584830268544039662427058413286141862", "418972780943620076757968070937376645246637635630333624261451425830186398269998972414203023069957291588835080825671751612930094540418282558405738295001203092713726987388095326769192699969216308782986697839291502761284381880", "44675930344807548597565141712951702335049870946876359027314742507173688383528319430427664761159554527672986389942105155856638071382094859946227472823573687962546472366814018305050568192034633999", "62057580281862"], ["9709018811830499466120970449561805942", "888244286710092488464496911890992251614776531665885946732853447441938457342058279870299537895", "888244286710092488464496911890992251614776531665885946742562466253768956808179250319861343837", "8623980489169251679949335042365454737049587690061120963942038877401945036846263103703545784403426520360003929075083934564265172090", "0", "9709018811830499466120970449561805942"], ["138438360780916936001236889922383190126182318997582306720549500707493348296343122969814447936468097331261830496500117342842371640215329712728524", "3367491974391438286140661190309761973416060462954472598893460881999945735047342329308321891654", "138438360780916936001236889922383190126182318997585674212523892145779488957533432731787863996931051803860723957382117288577418982544638034620178", "466190068877644229025041532435018783114692557193676973757073259417284179877982230085619589594294022381651270648834831961107582955583497501551544550881421925033240769679758353315565325428020337974600953640782638003482427810166921443338696", "41110227383967276250204319539435640233367390039554", "1035336463634218498313365079937832425858604426439912655088292638227335190059451597202550246208"], ["5708847305203572821788768397102058900123336997499247919381283879383693184602680361582100878599579897520352929686680373168469747012022009740499613140783391016192978365", "211624616177845503115112460186621339208020312395123900648977916976346792324817941112913012304", "5708847305203572821788768397102058900123336997499247919381283879383693184814304977759946381714692357706974268894700685563593647660999926716846405465601332129105990669", "1208132619781633721440367929169558400617538310153844593417450043501807692391705329227401024140444540796448429206849241585426264848639152431681303287619320971634220150367077044615040315053235470747365224403679580352610112126066682143371085187087294365650802960", "26976291361142792162167309519912888256155068176344812393053431057818792978", "210146372291478797387725612823468486367017725625658092349124297688507005760655986088850177053"], ["6362634230855871020758304692096414962532855863937113437099651603315237438165021794182723", "3617116487205288246026651318610739006341339777710539372118451002103364805726377165922832042046849086288493743874281448578968", "3617116487205288246026651318610739012703974008566410392876755694199779768259233029859945479146500689603731182039303242761691", "23014389178485509211291916576695237253352646845173985122701469818334442792347722685737304209741353775405218678723588492839389994302180733710645618925961056006530629467500849400543355992469490471344379157286769864", "0", "6362634230855871020758304692096414962532855863937113437099651603315237438165021794182723"], ["42521563821136044942613081570227395398449124833300745906447242029028160590112476829077643030560713862566871686775636954206129484201310975630", "20542338935494020209826966578117869788478388338", "42521563821136044942613081570227395398449124833300745906447242029028160590112476829077643030581256201502365706985463920784247353989789363968", "873492376081016863837638925849781755752673623958321065881775179056168970583075987501935205469658956079770355935162418848032389184619671109733737497932685439317992761519443681492794202940", "2069947533952196910704862013190021088344035325352256361274609668817835486948460164166116384514", "12693158121183043462962296493502248067089577898"], ["81603905599094328160", "12639054434885193958122739632345756713626450132548", "12639054434885193958122739632427360619225544460708", "1031396204966185878910435764370511932870671565280532059304587008951680", "0", "81603905599094328160"], ["601996384059440587139813599416121354572123626170233209055096773062676227028873733624010015545540779301408788180869143526014802085083338", "5137164950901602823923842541856196340851660706433189639553937840292206", "601996384059440587139813599416121354572123626170233209055096773067813391979775336447933858087396975642260448887302333165568739925375544", "3092554724759658540722004875257585112881203261247229447050557770757628643116963102159352085389293266694587412789420000231674952285712638579966908737947398638873229329564445980439998701336223729783781863628", "117184554090245177401164094291361808277755416705364878428213652984", "2796647056153066235756567663566085544940045263663795091553688841240634"], ["704308899680818879286892919941422468098979731827506955171311869198228062480", "107754820568576252937923784989397010928", "704308899680818879286892919941422468206734552396083208109235654187625073408", "75892679109958010881512938613695553333183991143099470730145546109106669500509515345241790977445381251760826781440", "6536217089541619188139307474158800738", "31507855699847489087712225815867597616"], ["97293997311388663329226664771509828897176713734551919401778319051883294067500726999285622119126826511809197971136023870673324729492493976787584158885", "844973826", "97293997311388663329226664771509828897176713734551919401778319051883294067500726999285622119126826511809197971136023870673324729492493976788429132711", "82210881155037792226322552553202075919852768402391083732564257453118519493699191550367871388788822376921652191662243656430168392819687673848160176030050344010", "115144391835148587583855721433328550104907881175661314983475380516559685799664908199518149475942260147368396676391280160994388871747719646865", "696203395"], ["69154107955759", "2911816564484041533952339420341074391", "2911816564484041533952408574449030150", "201364077047696695886087265623338606975938755867769", "0", "69154107955759"], ["851976330936788499861301578956735121443319537885695882", "28674393275117826479213330314173210750", "851976330936788528535694854074561600656649852058906632", "24429904374373407981967617367237120699767052404460896495076583998396888336262401745993131500", "29712096181511538", "3616079288723173907583484856255062382"], ["698496056419466424794872151982484081167079760445793832872797432302378945368725362777431631101985632992135813158955973513650692236", "66012587248614791762198366965938870", "698496056419466424794872151982484081167079760445793832872797432302378945368725362777431631102051645579384427950718171880616631106", "46109531867203387473792862153580921828791513511799510467128600580969659648717900323085496757889232766826614677534475933858915870632904556595362428573765609159613320", "10581255568560125889850288220606937898627769370000365181401225932939519797354919499281299281900", "13190700732813161058557623353239236"], ["29186983466711105669380155490228649856469684655990764311831338814104875312594854299225438189151492", "1108429444439808940762201911748668963738361216522", "29186983466711105669380155490228649856469684655991872741275778623045637514506602968189176550368014", "32351711868880479648274404841849764729265789038396251789554348218017795884167763471742418192468774473964002959157988832087293709213208376071350824", "26331837008770517942168492939180080110563305797048", "877880263030704092784749274100946999182072724436"], ["66843630756962151523014305001845192692035050102356453213368476009126131783586881699446343735487986463691336365692889251346190858573598704332890158319073551453855767", "961886788418394004508", "66843630756962151523014305001845192692035050102356453213368476009126131783586881699446343735487986463691336365692889251346190858573598704332891120205861969847860275", "64296005315039306914301047792982632664473172025884161420698613796050374825406505387419076816240277154117416328293442602125367242959604042462396043892783341576121347124274495732179797636", "69492201745354496908525590596054080198631688519167344038463206777189843179194575132015011745742528011747120650687893819855918759545095332925289", "893384108424760652955"], ["885683947575332377367414277999938835199629817576201983787191772748957305634471368664217585719981651229442295548216167816967925010563514303094546", "5619250613061406204857790184526513725773912483921199238686884215939597115", "885683947575332377367414277999938835199629817576201983787191772748957311253721981725623790577771835755956021322128651738167163697447730242691661", "4976880065391332815124657170031352606704589346977718379415429003678215805006003332518268170884695723624306576109573051884520668229180753338971372704104698877395022489658180052677547533469211434340139863440260993834790", "157616025438809481946920966396997360991260221798234157061132053855779292", "3414819982772175102671383905239348950372191962237227190374972885463151966"], ["47964576995922751338739579306299878157733150670460846946930015655571389575676157180948321913494807444400363680721911790067753348087843545822870435064650158571648183495535596958877593874013189615706", "2945718333401556782433615931022855105103375677659920263493238643629754", "47964576995922751338739579306299878157733150670460846946930015655571389575676157180948321913494807444400363680721911790067753351033561879224427217498266089594503288598911274618797857367251833245460", "141290133810740216079597643733649893361482207803649447242319496424287153956243614194510060210601968590019137918322686936182278852735103119042928985160098302275866600555633051906465069594418684481538843202698273886111304792042242947968186072391951313365821140207316324", "16282811717621298402816163436084052115380075774051306112362210277367361469194176002955858861634136909492267652779810277669454637", "2435662899084825050264544892012069192294839494279436413566625863146408"], ["2504707009805261566855462565952540687281746593126318", "7512397752172524247605680480637875395508983238285972222343003200086174882785413321476932", "7512397752172524247605680480637875398013690248091233789198465766038715570067159914603250", "18816355310311811644956301203397703741703800654058625807565253774761724394665881893300422167577218270016200473724618654198911159034999096376", "0", "2504707009805261566855462565952540687281746593126318"], ["106145", "241375396667992227", "241375396668098372", "25620791479324034934915", "0", "106145"], ["1319634129716157537763011710744259797280613068183161598866401378990868582109623357335436363271235766983583549983091805754767518410451959932877881975852502417841940375332385647745", "7957338852137824746379874365090139080677288273192675292544848136034243034846482362315498135566344602350618046225732184186176325050758506", "1319634129716157537763011710744259797280621025522013736691147758865233672248704034623709555946528311831719584226126652237129833908587526277480232593898728150026126551657436406251", "10500775930997466346636625896351660400291694808008146542166064300184035451455881328623366402566271560930292412082772425233845187344757689909582298325270108006239088811418989136696197612332905128098841374719063573660374666398489379774107026002647007966417058279589337862642858288383333505282376052859786020378468970", "165838624474515575324003353869302657078891", "1812587665148735707376261136046291298464900014094785474135088987516299580866439784135054136645452139437981207201500819656784602554350899"], ["3345967649725752470922422423544866148553829192", "96589329976", "3345967649725752470922422423544866245143159168", "323184773408381891318823204565036708063418043024429459392", "34641172586631883801260321764061453", "46794814064"], ["11377881381110693458691420190724691951531587691253541190060801953744563224395227787403729581123939682352400426587362108037245454474787649080997212703820245766697071519875453416", "78328179232131363088125666275364300959659330967380258933616246035795532333058189589773414308", "11377881381110693458691420190724691951531587691253541190060801953744563224395227787482057760356071045440526092862726408996904785442167908014613458739615778099755261109648867724", "891208732101568730098741770416963409858562478882364411720020233100446901008569241929632513312294398351990719006356817424809993704850379369812495989200327287307839822788509199227861723804687281868109139229143673670990073556815106044208617700748402508636668073921876128", "145259107164887605922026335946959551769489477421627114573964147717273463732326278201", "62741488495675032166797583537380080881613302221928433369692990875616365091980996445833553508"], ["348142607651193067112085241452129322806573595349340919448", "28642205203370649", "348142607651193067112085241452129322806602237554544290097", "9971572008382028385378603146031717047778299076686242782176947350396481752", "12154881412909618713036203233634139225192", "9644205686729840"], ["4437632716149164417836102093028653138520650740467168888248269121524960712498299198832858833052223321509170787279086782515777063591604224013458763190609", "326823095703016624901781150651586869810156439534591", "4437632716149164417836102093028653138520650740467168888248269121524960712498299198832858833052223321835993882982103407417558214243191093823615202725200", "1450320861884855971361977475165784492311217619353756796896988759270339422266647567172421559518853302765961820211459645960775692928706507853120378832668093256977846952867667214932701892647999354181855919", "13578087884528303915105045823114845429724646365239766083361212041094317695543550395812435692866668444", "129771983068485626771142775207418770143462697044205"], ["7471774538856655571165992349423684784293602158617762836979297328160", "266617205474309239432313739814234276014078946472355713570299584574328513273373843755825019743587182425658", "266617205474309239432313739814234276021550721011212369141465576923752198057667445914442782580566479753818", "1992103647484057102766782499241474859116686398307341253546024726130631433244541957914613376229586167644384308283040982496987943910474765784648015269862021289557387229929280", "0", "7471774538856655571165992349423684784293602158617762836979297328160"], ["15282845191361634171131489", "25808650101462830875172440717296057766703464218367963808533316604988996068792290343728799484650766259852691834767919914999203363", "25808650101462830875172440717296057766703464218367963808533316604988996068792290343728799484650766259867974679959281549170334852", "394429604098676176693340587236108083212913792322231869584829175811302459047406126982064777205933340364318230971721714872545240177572503728542247323997507", "0", "15282845191361634171131489"], ["24819077297994823345162493014199316508729722817899541245018348010421136444413125648777540935041379860233732136037323214209358005291109815799776286730278007965096957226972900287476027456352838463342190", "71504907409490264725861400140946474724548984939214906076410262937818405860547494881", "24819077297994823345162493014199316508729722817899541245018348010421136444413125648777540935041379860233732136037323285714265414781374541661176427676752732514081896441878976697738965274758699010837071", "1774685824182101662784790042841325310843702674929513086223242526180633935504550434106412913940861802981219282526234744023984905950097143920487925441161140825211238836571486701089200553763143872233680938895540243985098039160802656610633217447140788227320384374013303469733155176329390", "347096139232267421949333623703849625709468206079761689948798556965893053862543280407074011026819100735186152879193358", "66043193097509602365301219245769513134932267931865053151970778109912633183549141792"], ["10025693", "501208385725", "501218411418", "5024961404304432425", "0", "10025693"], ["98629866374700996253596581225255477547178719059068473794491", "74095787407492735148602394702322780689380096892848199671", "98703962162108488988745183619957800327868099155961321994162", "7308057610929261223462368369448224443819517713568522360652500163695349306766363656285604217172871784860931387812461", "1331", "8373335328165770806793876463856449613810094687520032390"], ["66028288301805038978583353021219502787468667123465420051453701", "2399762008144", "66028288301805038978583353021219502787468667123467819813461845", "158452177729450643879223381854490583453073014254686448407019017318200940944", "27514515221812340978873591668370851876251248850208", "2398919359749"], ["534406801047551095428827266136278238368130460905506650887896086925070033506930093229905347601861032823582219536712617934879525214619262903650989303984065961223215035140606794501049247152790170", "59492214897657400857275677521100375762248609411080440980751872679469101790329686616632283879054318703", "534406801047551095428827266136278238368130460905506650887896086925070033506930093229905347661353247721239620393988295455979900976867872314731430284735938640692316825470293411133333126207108873", "31793044250690553973982158615730646251159006801204791886320635391953179488692117686877077608510202144961185740959263155302504502337267649936196835169892679159037183845330512123876217724498448409311769526382387464623591270090826882175360505152665347375867545624371797375445121605135434865549510", "8982802236677091681919026141770561749067450523052795179513524524123287582656681110701362532", "40147123226941263758984781179830638498792240956165447759938775758741060503850132957964930186081754174"], ["40719099385949209082768370628000413107746204404002284158888485346475186213070983817147743400865580146941101681393308135194831936192705465113453642982053563255969917323943066738372714661", "825382369560784491717946540234724840420169082272393747974878712360247225541866294862524689510936177799463939570940088469087420554964921670", "40719099385949209082768370628000413107746204404827666528449269838193132753305708657567912483137973894915980393753555360736698231055230154624389820781517502826910005793030487293337636331", "33608826737555842958773751120157979679502834737993369011183196560598455138280153208917368975277955691241303564179304493787484358109856038463635101343290024835656308084775624103622612063796429880815443740248276837480294042905803885425744101629633212384310091465069841527004657948532003797993095099741934725260595107125603870", "49333619044488798139445007333227071994011984340", "142541739132183217997508030243241936760261241500610309006588606312271279003926818061972151631865414601692783339473216712628668449006066861"], ["27701864193907590585881523869262446", "69085058", "27701864193907590585881523938347504", "1913784894544229142265879057636380499131868", "400981992284172224128139602", "32995530"], ["39944087685405484524132071885018510273032450384027078353856448576975936652363342376363283836393884909096241009410188962407654935265845649555699867824226627004745945526159171647515476731510793190509880993469011086179162", "174652271849335820453733433723149356189897572885584602528840361838871725741338624015832199299", "39944087685405484524132071885018510273032450384027078353856448576975936652363342376363283836393884909096241009410188962407655109918117498891520321557660350154102135423732057232118005571872632062235622332093026918378461", "6976325661205145914554757951892352542439698011063366033721765497098653040444290965007973917549723630525883673184623675774983977008516405604229262690026321463910506296172136921443381543768076552157070216468617407957395506926753648779872686766321118901490543739136914929018231928513462580628875449916957204807438", "228706373312242640715393987156981604034980361127000131503707818580304704364592666823698137658665087633312103711647145128525674", "71920152059222908989353795358210802694067323322672380985669833137481578339921697570279876636"], ["1327647225167093149119057272472209792449237060233362360939671446619762856089142394429112829361826291171957548104970684719645461", "739881582806939602918563575468851511778344547155141703320755504754723166670390308652776361410285614938", "1327647225167093149119058012353792599388839978796937829791183224964310011230845715184617584084992961562266200881332095005260399", "982301730365870218203836912463186822377888874326481395955345562281046129855618323645302165517113928884922801864171543704726620947147295648119025901089328343827648722638910415503360000040937858291193159039071196410079095725496418", "1794405018341322457927642", "534141917379396974023841813109683208086564069458683914101019563069740620032666637148607216453641329265"], ["1678373903734614211527173178869917886421467589267639635211916056", "8348168923202319525476147451772843234712651389047966366209", "1678382251903537413846698655017369659264702301919028683178282265", "14011348864671067811840431832600671815233838977517462467863618391001129696524743641138046997746826391515419720862662951704", "201046", "7934400480680208295638280794845455427878105102189151061442"], ["333921184766716883057576587697690400937550318052410344158307249787049252109", "3661599596", "333921184766716883057576587697690400937550318052410344158307249790710851705", "1222685675237651893250001678252921742206012265810377222996278785864130627554416547964", "91195439591892745843960538742011157065233169217448849685285810203", "3211774121"], ["242415306703174247837314309645130582239466684212708717864907168616859837543664782225946424798974320152829274960614247149091943017304097841490035097664348145055446", "3566105792911786651630072589028473858684502129609471093566876346751210064612055825", "242415306703174247837314309645130582239466684212708717864907168616859837543664785792052217710760971782901863989088105833594072626775191408366381848874412757111271", "864478629524677150800654371769610993185215788855066384536569880792330277082357793832028456671201894589706807046335997498466219985429463273843530269589032857828657652887230493972801098023741200515263543996758031495971077425607050217674672272950", "67977598192687936161863843649762020573516349520534521192867118944245923344762479", "656967013703913122963776438949239275225603865789426637399716617567610333631665271"], ["7962745418839831205518973913337977043203855696641456990598535913532146807779330532254324039258343463198073213339916091714090413304560870943762905854616235321532997651138", "786914517505726533283736506927829167902406876042355043528307898207905046223296069765524975216847993587845161542246", "7962745418839831205518973913337977043203855696641456991385450431037873341063067039182153207160750339240428256868223989921995459527856940709287881071464228909378159193384", "6265999969287280109543313379919462941684292312202153627041369272657725965471501262409403383238365029343154743533508014469671826558035762435343137688443472701900815657694527231318159285891591595501152666144493453680330139581921171923253920146935543481000489315676375239821287556975948", "10118945885099755736952230767033022083513606437579116828", "267832761734866826310436539204205594130576548313850327834024533403542883403135640985872828304038612976537906135450"], ["76617179082072247503089010888739608761473", "933255", "76617179082072247503089010888739609694728", "71503365464239335343495334856970683574688484615", "82096724991639206329555170761195609", "684178"], ["184634416254236510123033202608022279844861645166679426869364893825340792717259260770307262071012111895538299747135953328838867372844013874764907372112409216427054426289215338813585461", "87631343633673767747729260374461906656372", "184634416254236510123033202608022279844861645166679426869364893825340792717259260770307262071012111895538299747135953328838867372844013874764995003456042890194802155549589800720241833", "16179761977377761025439129362178971043652530866978834857890882314947350598353110848235421696604851952978051084846483837103128746649777519897077383917321852174325531330108277275182469045257236758687772609164700787699382207492", "2106944942280763289351390792539913747055587312157666785316893342359458443689425187721915331267775357185465953409741684255091848465019231866294", "55425057631218619200211859223683906460093"], ["20784401793371214842916033263444568881663631860770248292523059454312959006647545893230330794414", "383092244986289375785384653708475080262651048", "20784401793371214842916033263444568881663631860770631384768045743688744391301254368310593445462", "7962343143719637690035535521906660685732963483533865861995595573465066416692745622804207130041951247051063362883100691825964691659509645872", "54254300538281779025892883421713439622096046540327", "276959384387844146860392346400761596669981718"], ["17866989173700960", "3190779144349528261", "3208646133523229221", "57009616427763834115967763482830560", "0", "17866989173700960"], ["2255578485537769985426371173039631667487781955363350664000854036971703358133529", "70991927697311363220347295149930001095148356222330094223673743822593902890675163939828027221801187", "70991927697311363222602873635467771080574727395369725891161525777957253554676017976799730579934716", "160127864760908431149008800996110039689116535368317418320815619768606603751429480019857485652167651524932142623643067669387836418165824055424741488114934158201652863185836698923", "0", "2255578485537769985426371173039631667487781955363350664000854036971703358133529"], ["15299083165975424688906585941881014106123783168451522003321699415666363431117569117333260010152865163287465286651937592923921126758829969384560937602995512847", "2584731487770146474198606183295629424765040973789", "15299083165975424688906585941881014106123783168451522003321699415666363431117569117333260010152865163287465289236669080694067600957436152680190362368036486636", "39544021993110862220361254895982156971164469976224784629417512852781094226388485580496799499925573188102876771007005716410907663801032758442532535276160383593226611865071629259385193864549764759866339767283", "5919022242102980416258552280739258785826264630663867568314405663981887672454598175768924246826859095635913897", "330804239048672160149605003495264161641157667114"], ["25868107892615306981364698", "40723654279115116792873787", "66591762171730423774238485", "1053443882673714872270862027988197301057134531371326", "0", "25868107892615306981364698"], ["66772327657380517154887839548714173618621819164877137488047331209570106119", "78375162948273143526398513716139869655935382413726230183953997682111556067069180886291693149", "78375162948273143593170841373520386810823221962440403802575816846988693555116512095861799268", "5233292060582683575897017702103593401078344455038026369197920999878373266820478150813008541893201265445384801592520629094238250935484501172416261494991924624115278731", "0", "66772327657380517154887839548714173618621819164877137488047331209570106119"], ["995827330316169980319790018772206198582266420408087177237488450177237068", "906543378601396567000138440713660008878121589031016196401086312326614748312392694800825786535565185865708181773386503", "906543378601396567000138440713660008878121590026843526717256292646404767084598893383092206943652363103196631950623571", "902760672528429679758353477667509611192366434608540623636752931248189016066846958395974101554177499325442086489910270149315127218351364522828257686941209633399807246565002729516414222493204", "0", "995827330316169980319790018772206198582266420408087177237488450177237068"], ["1696352977722464199441236967688843395169743120169909", "2687", "1696352977722464199441236967688843395169743120172596", "4558100451140261303898603732179922202821099763896545483", "631318562606052921265812046032319834450965061470", "19"], ["12583657852147493208620323108034361449677202820134658850016639384420942627271856534565045942017294696901152945790517656987413545501414410292617667711987800056637376519162", "50303645501058093718853904314920116071484", "12583657852147493208620323108034361449677202820134658850016639384420942627271856534565045942017294696901152945790517656987413545551718055793675761430841704371557492590646", "633003863701033601413658152832934691954112829927777693530473042108450465297972965202260545335671314423611155251028747610609736410110257846260273962837611942327313771978312052655622844328319591046839485887776408", "250153994343865333546429832637202813942061786939579928505383309644970585379738783831580011840079530197340439205597537685953504596", "12218329674911124847661394135083917978698"], ["7638208626082907321479877011059894315380971809761136137676610229236554161212225385310844653352390411598019729594311801949482603118976550099378451838775307506037972308", "192094123766", "7638208626082907321479877011059894315380971809761136137676610229236554161212225385310844653352390411598019729594311801949482603118976550099378451838775307698132096074", "1467254993169298814789463044840997489457672236265612692127625981058308266735263539758188431223073450537461683777199584253278391243200539038041703927191174197929567044828632671928", "39762843736893340662064804886916055063294537289292919045098710493558108090306930359008099369870812207393651385840548804273529071191070648043815142836061195", "65758111938"], ["6688166059154755779759942848424346891358761700731233385345484082845424142696854589645842636851", "94267095792194148971822736626879055194704553027", "6688166059154755779759942848424346891358761700825500481137678231817246879323733644840547189878", "630473990572443002206760807404775907503234563630757485016478662036835219464173808091895609287367021162382112983617600439670348641853033797977", "70949104806393896802973207395603822511574579763", "26182890082059344455320423956521537915568044250"], ["189145879285265356780435017003327449708746733088213665344411451628997996881388255065790519591605649462824", "31138007443995152162442934565170136031565969583643355101777127733740800913235220615685582182855515284987258", "31327153323280417519223369582173463481274716316731568767121539185369798910116608870751372702447120934450082", "5889625797185601130447138158566135002272294793772833606987099701136625252508785886481211618337955750367797128400089878033148658686364338053017967396861702702217846582447518190958451931672293809129732079384696592", "0", "189145879285265356780435017003327449708746733088213665344411451628997996881388255065790519591605649462824"], ["440575812994749218306712587135108578730731598812976691678313344", "2290060915127979946572510417975315699881472090695859636531909327", "2730636728122729164879223005110424278612203689508836328210222671", "1008945449490009154079213324026517669956542691740048603620235722930752703732358998601270888327641878700568743587080935302159488", "0", "440575812994749218306712587135108578730731598812976691678313344"], ["7260612605293942", "601393336642136584753501303865002164974331925820703795", "601393336642136584753501303865002164981592538425997737", "4366484040763680021552185296721783617625610348444612018887925289909890", "0", "7260612605293942"], ["9069000718197122448563981781954941598833868575638697974415265163457723501974916353101208023168447385520363155849820686930920929567071213091156637342689095820444563288268716153205332220833495457949292948985", "19930838803856715327719996840103545505040132763", "9069000718197122448563981781954941598833868575638697974415265163457723501974916353101208023168447385520363155849820686930920929567071213091156637342689095820464494127072572868533052217673599003454333081748", "180752791426447628223164514196951880468020675059831718526805054870106183955436474192413037409095962012303694577034356729991331845307053383440517787429859445181151000481665432660216836846363782163734259060876772178231159493062021345871046502364186095555", "455023534505844591375750932685235317422013888388872955135192604234055537114976911007630730047532475444921826523253243472517672209863036562030973541979127258569", "12179812754502304164598007606183910389303552838"], ["3011544560856770750249209332", "103313086088224209267140530781434", "103316097632785066037890779990766", "311131962474318927757127659343209902869739595481666605142088", "0", "3011544560856770750249209332"], ["59886186883378096048562962404343480645820338458509050004345485796341203654", "68949875564616382221635868384078874425930174791101", "59886186883378096048563031354219045262202560094377434083219911726515994755", "4129145133648281483428133750506036921276053555245713315449805861127222790945390670239890039451325980070861190688978347883054", "868546699946626451957426", "11898098248239887532413817217716316256254245537628"], ["553463714041708549013817355658224918806383725914324969", "320245843573811229689304993258088468032101309453478954445961491769359153507476615522130330357435834877753551666679176", "320245843573811229689304993258088468032101309453478954445961492322822867549185164535947686015660753684137277581004145", "177244453990781585781919399156340848992924141424105145877000934545570114536553256227901558280240012342596337690692443275814873092642266511138251223955415240086935929145544", "0", "553463714041708549013817355658224918806383725914324969"], ["2696877755536045166415574095410403399291930738054221723914531808081550700002469451657909599752813517328681584420891159688733543352427225", "73194151194887171336695970480436739222689172991483275028013783062539537049941", "2696877755536045166415574095410403399291930738054221723914605002232745587173806147628390036492036206501673067695919173471796082889477166", "197395678192833253070718963269423671396149830889408497215516471234782853428421454849346346648626486058430951360080625730838192223409521415915785693888277746512870362726420684085886532348049128087443366258393043725", "36845536310071044045067288322796486976567389335305460712455", "31097603583241696323936401097770472158950914369744756658135100617696576712070"], ["72962308964556201524824216166374983188334115667468007172059326365662800455829322442509679473258936988057273529297078990260092634196", "86491800586640975557193114612224523549850864771480861579728513014733316824249252212600085618", "72962308964556201524824216166374983188420607468054648147616519480275024979379173307281160334838665501072006846121328242472692719814", "6310641477303282180917377825898737044932525392164638767168755880289734967071950375089707841872377479003302372872011190494235347424907884156602412449247240333597429840286553515810016288323736839882737809367303510680754593128", "843574864549941382069971504915288092071", "76669326011959108026222481849172822189355813466956222888008420840410827457641886829625699318"], ["3403603467130513747669732647537995288026871221141416556348011640072865040011216660693237526034412981996168919848279867272402371976493181803359", "118514009935188988266026180454044714229709816745507777680966929704154510474424825300458191223375758709885994723869300610828874", "3403603467130513866183742582726983554053051675186130786057828385580642720978146364847748000459238282454360143224038577158397095845793792632233", "403374695118949393350478469762130731603379234891329481727370966929565112752814838587572215909983092694200275586794015040496112978446361171672016981095366546334454390769496653441940989532666210573740526072852635148334741783499480504587053656944369946701688323067387766", "28718996758204544", "73892243433119276113022006404719002813308144484716062054895726480784181604909483593525568603634317396909481397653561308599903"], ["99926457057689941274910626909393857012614532", "40923217489035534922777628637774192405364696362620779377629411452165846216306142249586552318009159953615032103453244581443", "40923217489035534922777628637774192405364696362620779377629411452165846216306242176043610007950434864241941497310257195975", "4089312135080615365655792560293222000923272529232992879870558600337644590363703431604483733893617288029295043693447592532412034716560456744767560550838659927439329676", "0", "99926457057689941274910626909393857012614532"], ["321954976193360446989183650158639562356371931037358546847280510017558003751615130381833205557727622856121041401482868392", "12348428489973059278630672812645613077875486111941192111717541692210133944662048950577626215343882522543247903998371928294589178", "12348428811928035471991119801829263236515048468313123149076088539490643962220052702192756597177088080270870760119413329777457570", "3975638000514690193133276415794124489666455203618788759771212773210721218630638447462867771428198910074089553402423955731878222263494624777865887867896873238441524931508196841670222364093524714131267511420978346045236638823965206458105956681461776", "0", "321954976193360446989183650158639562356371931037358546847280510017558003751615130381833205557727622856121041401482868392"], ["8639189778016114854738", "23093349437304892691714983667269409860", "23093349437304901330904761683384264598", "199507828398918626783247034571654503612500500145004884916680", "0", "8639189778016114854738"], ["69722011613374199454234504071710594366584565287207921864181581371710000810614146113940605042555182891065381231404891130881936316892907506716049830665488362821832909456890737978249405423558204363086353828965292987335", "785911911", "69722011613374199454234504071710594366584565287207921864181581371710000810614146113940605042555182891065381231404891130881936316892907506716049830665488362821832909456890737978249405423558204363086353828966078899246", "54795359385831110251172596137135354257588310247973841726617629066842608074881312656040284649490780108871698589516951203418373686189606520949456056789540360973568054393954972002686266651042392810721734195744280564351348647185", "88714791871088208324958831259793178483312953997471507801313347663094523084043379658029645312953124196975532581545123230588035097094879767913391289301236157014845025623858674382973444238279529476537420526465", "558762720"], ["94884944467925275119660141052151635514619992072860802471734190167234020044740359701163704139159626182028433660879245934636713469143072299511519468006151", "24347013487143179654490151907263134553", "94884944467925275119660141052151635514619992072860802471734190167234020044740359701163704139159626182028433660879270281650200612322726789663426731140704", "2310165022687408305811785784544056169219397811240907350187765002562930779498663247781690458597523137793984968740441766217727010965441233075261909192850628481938409828341240193944553344635503", "3897190286522441468467794658167670495333434579014316012925254161989131260960765357415529387904267312106634691587012", "1453148660212691802703374594204780515"], ["914483951609874970587568164331865121936022793272744091980720934165092003944984410521601946964399897262682444545109379829042363361665546824156593896", "620400779808389473421621884236398", "914483951609874970587568164331865121936022793272744091980720934165092003944984410521601946964399897262682444545110000229822171751138968446040830294", "567346556701023935939560152717966360184098671858091112558508370979818122178796831293042037970783013614946999190528186470106287416872894434946252999685775436924588575591390547826608", "1474021280070461813812684632830464943099541771726257985333714560323529931598667935840987931585950693461049555549764", "120365918651866234200555927483824"], ["197303140435637361574706118096801109302284372650", "9243895324129621599201808976452943204475274059769444", "9244092627270057236563383682571040005584576344142094", "1823849577309078278210929577962933405148875407518254853245750190172917987133895355107620983179306600", "0", "197303140435637361574706118096801109302284372650"], ["279117870920449753311297207400727783448970971098058901782328094530550429021600951812312685191627657598417555198251332666483068161634284409235970928473546576149376145765378817153684953764045943", "539510715204286125239226897756982050018206078869899225051597883", "279117870920449753311297207400727783448970971098058901782328094530550429021600951812312685191627657598417555198251332666483068162173795124440257053712773473906358195783584896023584178815643826", "150587082166589462865912939672273709647291684818785159145088828520676601527725632864717555045931810986823934906961022436110022401788614324229629834775189394606020659328065849423625474463205980615980883371242732174435477247577972865520181943271827173538669", "517353711528716474528152733989045641628281865717146961185782020417131361703255492250450666108738200139483974967425765572636096532", "490460434515609374547487515622246569276272277739391943329204187"], ["1452199513054226855688258263703494132349311621736457930267331729335056095036928803658433573361576400494920954589642421115707171150", "5678189635559", "1452199513054226855688258263703494132349311621736457930267331729335056095036928803658433573361576400494920954589642426793896806709", "8245864223788337652705021676494013464999432669912261317808195787636379397680560432291910797842779592059990242371874087551123708322781338922850", "255750442704483989678596162890068548634121710352138299829869352316930698474596567997703742039756657175240147334157003", "2858649501473"], ["704125372243659283555473373145613491575261464367290382890493963201452041379328510321280462887207469438208322354923491596788413847317289762010925150584684873005953806409761062550481", "751305687597418211377311517455044456078301149607046679648", "704125372243659283555473373145613491575261464367290382890493963201452041379328510321280462887207469438208322354923491596789165153004887180222302462102139917462032107559368109230129", "529013396948310489896763323176478242100204457649146211796377561568520693292024295732167087337041306523904871764893471376800071459908828701653276931912729083594863511771812043926511649723444148449176535869427258312811965560974929435310688", "937202238539367795985380066225242535745922574138367596087498221019208790118050428743963265743484161058127891344536645098200", "90527325375854599491197969426346370987182686076161116881"], ["49530285006830651531195184901410816178463679268045549656703997117635071", "1502283625025023080815130155", "49530285006830651531195184901410816178463680770329174681727077932765226", "74408536108584101267918055790765973191567976391676464237037038118206297983936052752056108657666005", "32969995932695892001416725210740570599775542", "247958599309411156601966061"], ["638051794242158650460474679611448163670546824583643732466", "258443303894243336281274971612246741773785288209831837885224275379305873948753958026230317634540454176094560272", "258443303894243336281274971612246741773785288209831838523276069621464524409228637637678481305087278759738292738", "164900213759593428678389090888288507164921757037179482503257195954416018105126931729891755966832429218094348010580950917255693224726105243896855248072842116109080190752", "0", "638051794242158650460474679611448163670546824583643732466"], ["3965025091066885772165799853367511", "84228134835642586531650419059200662761825106799616611", "84228134835642586535615444150267548533990906652984122", "333966667997087680542699637131809969036433317392208141534940478822105533385192083325221", "0", "3965025091066885772165799853367511"], ["78323955777188663415693319823210418657086777951816330354817721900527872281287023408102689845486285480709543665092475146902161031771032313031493815030389", "419445056207478250917488868611747127811585644177711250361305359370065792", "78323955777188663415693319823210418657086777951816330354817721900527872281287023827547746052964536398198412276839602958487805209482282674336853185096181", "32852596033354939798550487188608818692249507944854793051542691912530771939509244615187541667498231545453474622086383776849913456813701000446576113584996814277323654672468875577648852673583995766163703901675973156973409353088", "186732337449331539270716084840208002597674399839504267861020952102401176879840587", "240156761064982549279357385574868594605132835972304822540455465153130485"], ["520446670915191621091250568315262555317790266214025550166145379052", "313925631013578486779895386147993840511648804636041421583548010539952052849805836998445201282", "313925631013578486779895386668440511426840425727291989898810565857742319063831387164590580334", "163381549575967755377646237234623499378338593631238033634308187112627162516353244254049077138162787093913914581276601730750724279269431973949559001648326344664", "0", "520446670915191621091250568315262555317790266214025550166145379052"], ["85520741411171725300219146195658499778443848879656988145127171", "45243982909141932883030814398921505562497612406489101585487925829", "45329503650553104608331033545117164062276056255368758573633053000", "3869298962784200286534578306052796444036904356282115563790221828979446291774355510362165232625269549189948692539020382220599759", "0", "85520741411171725300219146195658499778443848879656988145127171"], ["26572243045289590935774606515378431943142242905308977681692514168327142419094135654057204089144265117782536892209844114110415715969703466336413532527322342956375377307568140467033948584355593605389409714802198138366", "8818230334646632106963631754767788992515440019", "26572243045289590935774606515378431943142242905308977681692514168327142419094135654057204089144265117782536892209844114110415715969703466336413532527322342956375377307576958697368595216462557237144177503794713578385", "234320159681575672111424399721351156270733254756645010257870145243393930217900253567826145279840761579113337775704484777840150561521583764255969810421007979033988438144331019806869524895660421182141255018288012792754231402193218857046346307800737256753135668954", "3013330570521370398123289737088759033396841784747542579528955119431416104851799118859998455541305741568736239960079642323999113006482618684420680436658637555741084128216", "1197100965603107845201400489950354401944662262"], ["828682014858604714829903635512708083", "996425291051883809233921888132773985142164542165034882546908156232319729914556620089601943688631388", "996425291051883809233921888132773985142164542165034882546908157061001744773161334919505579201339471", "825719717844946706402864616125838554981802132298851745654989361214219918555133868239834817080294908539321647196522629857967527835109204", "0", "828682014858604714829903635512708083"], ["3897555489760739085482626878385136840816510617666006840888429234991353910999874579142856051793279029262823863706586226260876043797591343392630374725039318337820511220225886233176592832033216698045515030", "2601841051636934057877335903528904921992899867151085569355792669513330989066947596824439959696356302646570313152777766229731510045317834", "3897555489760739085482626878385136840816510617666006840888429234993955752051511513200733387696807934184816763573737311830231836467104674381697322321863758297516867522872456546329370598262948208090832864", "10140819874292386954604291631696634523140137486208524024228712580319412351294351756284705432347548969654357418310515785607125044363241573002896558941700044032822596217415001937754177948768497576382164780346478238076327335322802115729137364963958990909226275061661646104042520446234741739798761907187208890744111449704393377650074574045020", "1497999075427230030153853497133402537461797914840275373815707066025", "2091575740033275218303146743820954905604147281041155276515089222116098208274528988671070511071016898770939461688010781572109537297525180"], ["3965926005931962201918288375729196419993621311669581922199561122029533616130496770608669781757975264293466603922759964052208083386540191737282407764327058396339209647364931191851337920293201", "23536533439485141132820523687629773391641965616462", "3965926005931962201918288375729196419993621311669581922199561122029533616130496770608669781757975264293466603922759964052208083386540191737305944297766543537472030171052560965242979885909663", "93344150057141374559534071389869190710702138380669467026085554281809335349179465192853261189939645649544248671889016769868436496696310065860613742492448052949557540071407572970828798464239793753126873227791795741959080447075092799752274862", "168500854899841884327669040069221825451280086276033861599186248764085514390892469149619720630368711830283604620512260748106619728259857607734", "21108979677529445857047764151791774180040031376093"], ["16062432647043439783845013857036", "4279195492398536204621840171540749077086061628391776559645321545426111830499808763705934604143601941696301138024211548925774830709987169", "4279195492398536204621840171540749077086061628391776559645321545426111830499808763705934604143601941696317200456858592365558675723844205", "68734289380183375595349667910861376897882678537257698963911471169122485553761781221110508209519411046570993456859581537612878436174820835360194733727240527002760371084", "0", "16062432647043439783845013857036"], ["859345397314771731984605273205927260265955214502240015632424569739116804832263548335115759489630399003248985380993406410262949610722147423718715393556875", "67291331396180841109138485719491444474352088674338915027003309383363775093613095257617509650", "859345397314771731984605273205927260265955214502240015632424637030448201013104657473601478981074873355337659719908433413572332974497241036813973011066525", "57826495914490998117852422217281914790255551452870488846739812919367064691378304726622359203345550461347428249504877582095691928355917434939307434501978684209345389924773252450825620084224993515726670980261861882211192016705929063366793136343750", "12770521543931650947837396335947317319522547400971623672853752", "37635029247195593733804004448229923502413310056064816064297443872323425259423708816494850075"], ["87117544700172476143492395236778197267581991256399905900506682807839965887644620673033229559354625781910093749331231740943532329214064061032199545298160955082747805563801463852178803540278628856966", "332780012346849896805", "87117544700172476143492395236778197267581991256399905900506682807839965887644620673033229559354625781910093749331231740943532329214064061032199545298160955082747805563801463852511583552625478753771", "28990977600950644402260911024875452988223093524223402401528204368275631071282127332391703114115732398957577955678480743469382846948048870519143503394394180279203325955226834501990371048915720376718702843577552205393630", "261787191141070143093033501987171463858604003485649012417697318167989871715468542065674838131959399782565357207507697774082430122126580636125980741025856084404829557044444610897", "60338688115800372881"], ["35998257439321920047560352721069384203370479339822109723637203922149226686997219438", "947735882453984742789264479175", "35998257439321920047560352721069384203370479339822110671373086376133969476261698613", "34116840281061481022660381271124091672180583981329229047848726171667879282193773398884798385019686140406256203650", "37983427773264390721528377737229516923845873538011919", "915404616166057436872519932613"], ["616757989421195699177633922249946058929071970566163424117035952819934294390853755571249862376989819049269923126576066645467272825327667167960847404282213730657514323384214659516226862421", "334970496715115115232986201534023", "616757989421195699177633922249946058929071970566163424117035952819934294390853755571249862376989819049269923126576066645467272825327667167960847404282214065628011038499329892502428396444", "206595730069433636942402074118414481683998644050787146854730018417447964407310463858107187056368652051954427759252160580777897336459595132069094586706770554002668300985221886402603604973609956308085253063452470371649683", "1841230781425310176416707475094278261798348507825417373797099433262985991911725559075694232273537937830260849029890594142360567568783816599758181152368320", "323961054406814654456432719511061"], ["1007803885235458932052874656039132543451417374447841898530820664454686707066235326044551", "48303784310638450499295079", "1007803885235458932052874656039132543451417374447841898530820712758471017704685825339630", "48680741499837034711465102151094256203122835555638128208376262560134875026428766394820246223593778935954849064529", "20863870183634860299766547791978464771505323125299273070433393", "31102577230960771803871504"], ["62723945066145515038424318761658800975517151743365045100068123289409427994712", "2815842994038310898337757220568164896303069", "62723945066145515038424318761658803791360145781675943437825343857574324297781", "176620781272949725788240928212645799721220087963620849703504336848479585178357101657745355527735131435873057962881371128", "22275370181840516920508359190819465", "611420337745915747290416689891306323556627"], ["1989989953736837544757673694196605072663951730265140240783299280221118499", "395911447428761164609843325789047740210836", "1989989953736837544757673694197000984111380491429750084109088327961329335", "787859802952644819675032563666081947180015496329267888969802159799947751411090270308625711257057113952841999855164", "5026351136499807689910028213021", "59380152586721175403287027969949360622943"], ["5445212694029845393240804402686683041977867259986752352708454056731526960032585758165544094146746037239947660788761612095402169517958466879227697122696751819884092367893792670517073678021508931549373676430", "572521646118715362358406082623889240940899509420234633577296876517684653957230", "5445212694029845393240804402686683041977867259986752352708454056731526960032585758165544094146746037239947660788761612095402170090480112997943059481102834443773333308793302090751707255318385449234027633660", "3117502135052491855754088296373952338206815729868095764428532103345939102685709098393139524639790231849715435805610997973780178940461815476268327342023065239690742389697692571151122931432544506993111806315758763859277896124212845897067962359581783735030077927741091277005793079088900", "9510928942066152058674073868735513871142083080147267961040720577430715351624124933003906980235586789792735369565857161500328856", "230567085169118420665015349483471874264227952385852301028179499024342614847550"], ["10509393905101902813892827078704673875111867779329407741773495309022573149675451699414105501883683116004122338013159811188544222396987849408935359", "6693650058272374293805467799041774445067351169209063677909030541758889758530932299545943101", "10509393905101902813892827078704673875111867779329407748467145367294947443480919498455879946951034285213186015922190352947433980927920148954878460", "70346205125292687009349703431049748830945076094779171953060573676457283058946261333476461665038095725701445663787502263527659977598508287364672171743819191733622478634993807399481469463212481440648724181934994641950162861895528001008259", "1570054277354076221840974001804639300534580735998178439", "876025044064300985340792722769687992036405890812490000117153533090071557220778721069936020"], ["85271687001563496063543821918472837779129904971742649011464618828568687076018497568773081799813747925725035213518146888", "5995636544967878855688250800500063532097352681526934181273959036982252572507974086438661095569808384", "85271687001563496069539458463440716634818155772242712543561971510095621257292456605755334372321722012163696309087955272", "511258042837636544972663451458420674867143097372270418611435842993391222072572729691604895749136878665959159347793770356698422316684316207702450542535001867594072224454791916617607631520697268061707827618792592925908992", "14222290888051208968", "1630054920513262109941848262926626772203224021583776928765643423322909204633898348049950962215759176"], ["5847835005222931", "779963367534146457174008900115724393", "779963367534146457179856735120947324", "4561097083457740198546657426122540634429475519655883", "0", "5847835005222931"], ["688377806641116796", "1360357213011910846157931006529975440905426183643249159484251019796324226719946772301246522797282763702385928542972364887744134182", "1360357213011910846157931006529975440905426183643249159484251019796324226719946772301246522797282763702385928543660742694385250978", "936439714541561697967485867300897804139912862423267116988980316718892264325675496365383516376639209140999745426582857323012134270948183666557920872", "0", "688377806641116796"], ["145390538899875508245034731005405742964120167877189159143690623967129571495659931843445883500287908036294310649888615581", "76115369454163", "145390538899875508245034731005405742964120167877189159143690623967129571495659931843445883500287908036294386765258069744", "11066454583503881682517521419381907658041248780127907334629595949274276057987505189962135279970338514561864025204434791532327707113703", "1910133786940761164366920671606176539529673858045329725094672273466320944478049009214705525874933382880360", "56427955676901"], ["67748409001028722039216232043132584568005071952613136198627910241392799681907120128675217", "18545626910269465857740898221727329464005428133", "67748409001028722039216232043132584568005090498240046468093767982291021409236584134103350", "1256436717097420368275442022507554111972756712065175122244473595251798748567370660983612191703844841134537946764977663152399114191679861", "3653066533087305881346088818184821067467277", "12010068270028714306587306780236622177775971376"], ["8495705694669388376310341974657418686262031653961229008742009793586729449253975233562193930201921238887733056350876574548626660", "3998", "8495705694669388376310341974657418686262031653961229008742009793586729449253975233562193930201921238887733056350876574548630658", "33965831367288214728488747214680359907675602552536993576950555154759744338117392983781651332947281113073156759290804545045409386680", "2124988918126410299227199093210960151641328577779196850610807852322843784205596606693895430265613116280073300738088187731022", "704"], ["24830292413605617358041408166718444710909021212009673409519677637605167413719182955750425809863983779594913405969691571991128248703405107412083313079", "375976385353770706551213566340596206589502917452685816726167219403454915861718225551577999611649818307352712706694571954013688655064", "24830292413605617734017793520489151262122587552605879999022595090290984139886402359205341671582209331172913017619509879343840955397977061425771968143", "9335603588944594921004156615735844565743782990478812689993045564004784871562930575295871999485258710052622322308943451668189596806366038857351081357231561874159511614083699019190643411783326520485193588011310030137588275568303669013623473700459829880017189507694664544368750782056", "66042159510209227", "164842346450757232285979412523472931896465643047452865026471832139517954108127208414553460691027972320131500252615968628117210237551"], ["54398302492238527023424945914635436954395732579348046427789348215115945107900966350544080581765911632804018274692351436569073451460288484181310025342369547019362344320356", "646982977643452944603235557975653277912417463169277540675128", "54398302492238527023424945914635436954395732579348046427789348215115945107900966350544080581765911632804018275339334414212526396063524042156963303254787010188639884995484", "35194775725177749527758827964195039447522755308565667054846856612597041063681380049702739495066307438997120553021006582648676211442583148057235473046883104000156136816010988405124365152799439100368920768818938332098896400553305568", "84079959399205382131539065669577420514113911587655545140091106035528928339794025607784636174818642861325300970", "463760089723240411507712153155303745446861631377320751046196"], ["3249984049743993218029792488307701327788336870346977319257562347423148842296151915618247858931217162978016161046216360759028815606343667719690450643667341602896985013905410102715795549967174652071433199210549", "2202389155191164899", "3249984049743993218029792488307701327788336870346977319257562347423148842296151915618247858931217162978016161046216360759028815606343667719690450643667341602896985013905410102715795549967176854460588390375448", "7157729625700434062403286882530695967318433663987647246161683979892247867355199435889615013649901445202202673410679365366020316760553349862246139453599907882461788723939099653636445484284210741727147158926863347508426479319551", "1475662937262283359577297207207109873586172666783302360392966835514664408558914049382516287922479996243652204478267242329756891002928665872658451011994672646166646978863687828063548347588860", "1403809691883785409"], ["882203712243307612131159683525094372997128118", "243920271371676543463004222202147176761879865195237100207", "243920271372558747175247529814278336445404959568234228325", "215187368895488037084218749323269053935915558347193860356295082156093038134713641029516207297183320426", "0", "882203712243307612131159683525094372997128118"], ["950813825279457715398374613437682521080422666126559775823993645754094698519528262690081187901044098103666897809316395350733630323806", "6678127016872461438309404472490112741588953340046322111076956214436099190046207344208900187327", "950813825279457715398374613437682521087100793143432237262303050226584811261117216030127510012121054318102996999362602694942530511133", "6349655494614598716599307188770301772088250188064760099581705754470184994384627919412861560968451786448421227123529340775716656929607655754454013035179403450093035932053953943720306294068115423241744740461582472785841067606562", "142377319700149739450559750096993492801", "1354177624748568886625370883911498695601423389999216318761765637421981081430817741104704390879"], ["896903865162668377423985504788927627377940032465418435832597243600613281323642606936496297382367769620540508091966688786109496871290286796794439686302179945386739141948833911938841218698165824", "23", "896903865162668377423985504788927627377940032465418435832597243600613281323642606936496297382367769620540508091966688786109496871290286796794439686302179945386739141948833911938841218698165847", "20628788898741372680751666610145335429692620746704624024149736602814105470443779959539414839794458701272431686115233842080518428039676596326272112784950138743895000264823179974593348030057813952", "38995820224463842496695021947344679451214784020235584166634662765244055709723591605934621625320337809588717743128986468961282472664795078121497377665312171538553875736905822258210487769485470", "14"], ["518508879734170544256458448494900579619366822659973525681451212785", "6912534374623918709508009", "518508879734170544256458448494900579619373735194348149600160720794", "3584210454710193260663244423366901984445657560433142118146300830910320648325209843720695065", "75009953171101645949469895850652310536881", "6816693247605651291832856"], ["363139062300383767148416748438111505696556838211640569942194996474", "778807846894417125654578566047764220084761211895296817", "363139062301162574995311165563766084262604602431725331154090293291", "282815551233419482981832192247480764141993981847323513880414655390387654024694636356324799493979782796590024350498423258", "466275556606", "568993369889485461832910394683319636561938401939873372"], ["264358502181564173082364421515886228824309865019522794095855704023852254246368182944977931993447164031391386278992608256021815835219355951508260834760896197640531987898016797612989740966470505633908242246985833174466", "2476271262539448808123714126009334517635", "264358502181564173082364421515886228824309865019522794095855704023852254246368182944977931993447164031391386278992608256021815835219355951508260834760896197640531987898016797615466012229009954442031956372995167692101", "654623361960179546931868049806359681993922382100687544995505337116564298160242855205321438575203077361647970548984624410681764136857869262835654562074979879729492190027678933757849364115525296234272911681992383023970772327273751563315207992078220908707910", "106756681378461358791761617233199857663667953853566076638814528465728264290537393518511907064566416692520468418241327208311812822968165550731218243686658640950247258583521004896", "1280976102629626349699599410391199833506"], ["666314659913081588592224057898999108", "792131584234755736177337848297191563695458559500073660448850680571243215117953618830037647520392835360", "792131584234755736177337848297191563695458559500073660448850680571909529777866700418629871578291834468", "527808887155791809606442745502319489685755980240698626425090387416207163909644350015603587506009031460095001925170235597883826318230858880", "0", "666314659913081588592224057898999108"], ["2967844781092503950377000778041840318341973343667008600528281596553879730311206109704848956866967169276324272939877650372567860297836", "7428466488549412999287268271813065368719751201295441679", "2967844781092503950377000778041840318341973343667008600528281596553879730311213538171337506279966456544596086005246370123769155739515", "22046535499561934125982263978703581156867338368577259668315778809982994896434988761324920143540026338645838179099566510042237292761805616188859305146043314994114150927662102888866107906644", "399523210566713766801698430923853050390440135535507785159147666735797081294626", "1601830761960347612810554109700004051612925758061180782"], ["40804827875217069183120215508913120359938587531091219399510621066304550", "15874740525159738362510327358918979806583284487017", "40804827875217069183136090249438280098301097858450138379317204350791567", "647766054692876147720310066152532005177756615555538541039768670043427417282377319149615245313007519885419822990643027350", "2570424871546457841910", "10845387598400252507647857149875148248729832822080"], ["63265688068131393552968763668329081940658400896547163595755794254053478560368921195558846101257412150005870605125528589155488725152680705140306239937181255603917781382201699899970468472491524", "177973629625445497194508529459839081910611800986924856054775658136631889645069868703948555099199", "63265688068131393552968763668329081940658400896547163595755794254053478560368921195558846101257590123635496050622723097684948564234591316941293164793236031262054413271846769768674417027590723", "11259624136236583088574179847132148353631689425944116063532293415838291117608723172090170263984778177809620678824456276222826784386387736087381380051506075337828798073954460432423355050745588518019828436389095541915424679601404002496880982475324299443646120517987270059468071550506689276", "355477877263486917301993710323003641630990979163985753879744651826641276560564699067590504974700", "173274645757120701159221202719844517935417339029596140294742140551564827488468833683406987226224"], ["366793893941103636332410650587281888895179273676747724195746034762924843984047741837971652311555", "184770762303721075596044192276085019048632535118791359339389713104273257735", "366793893941103636332595421349585609970775317869023809214794667298043635343387131551075925569290", "67772787391847937995963754565141753959445498034876029517402711577843024336946370021984734126844077069301524801910076147505990092162811383360675846614998744821583033627925", "1985129515990078368234", "136666023283696098342805741638058184656964787208024077412919602259533521565"], ["35669462939261532123011329660869927213062086017918949616198439516721572771421248621430896913364080235", "404944035478570022303427745547070095968453694783997241978419091225928905099298", "35669462939261532123011734604905405783084389445664496686294407970416356768663227040522122842269179533", "14444136265977860412568004999985983848520838574426128493590913628496022026297346986423303888768631491909116317358424236040956561021826075252851027860249988994838100528919114175030", "88084919925062558409777", "212231575736628981132088694825143205198301028631314307108511985576084205043689"], ["657867783228016588521142414377256021801367399889155874201956412293790107001811559352789936377940581300166118811918308333072060894875389542198763167475451840854", "7397353668190417740889799815009418150175143359", "657867783228016588521142414377256021801367399889155874201956412293790107001811559352789936377940581300166118811925705686740251312616279342013772585625626984213", "4866480659446067088548178989829621810272167463725631942705931709272382363869053808336179781062478495640623690190070067683996213258946471318750038648501395536115002541332610307173221195562069285549902988586", "88932855279981213293511666437611907058018753361350307729110988558485498617270579768644674450060802612218845543244", "6028863992909333655908198445676637329517924258"], ["25780286", "25362270769824635324011177727059571609197802231950015759720019161348064242181121874093160", "25362270769824635324011177727059571609197802231950015759720019161348064242181121899873446", "653846594055519268498710829000425695122599572111109743990089373905033241709802585714977655443760", "0", "25780286"], ["5145514862117431977438344939592314341792551", "6566998228492780465218295734331497694616307886187716821914929102165958313444393660414156123811958001884029289549031667998", "6566998228492780465218295734331497694616307886187716821914929102165958313444398805929018241243935440228968881863373460549", "33790586984208449331290030157342992375249219326449567192764513318230896098260568840738360746291418849298241593440340498898117879375103089478773739201740756821482898", "0", "5145514862117431977438344939592314341792551"], ["60436208567870230674428103", "1148951160688472117453762895059220", "1148951221124680685323993569487323", "69438251981665084746450616138310965963239624547177817259660", "0", "60436208567870230674428103"], ["47927734099906794677679446544181400419200025125021615875012988698757922387983150976545046453986028778751874789447504497477764147945940798919802883622017068656382763439749131371167953799680583483", "4401476252294345872022573724205331525298006383166121815666409919614175449488240797557821512537", "47927734099906794677679446544181400419200025125021615875012988698757922387983150976545046453986028783153351041741850369500337872151272324217809266788138884322792683053924580859408751357502096020", "210952783467017682874949186482202177510325956246408305885923847174952663412565088779235477804857291912672997372364548371361107690459546556651239193808258584044654477358518125877001124406304236842650776482572642496704113446851549090310344963362909991002316207565560032966115336957759626371", "10889013447459504438789698811040382458369697920208181448844801777696837467154943287628070588400928815", "4137206060693535831030180660805907325833698058649378992481480184975811981474492719040713529828"], ["276070535776689574698523055001401403725922061673898216921889843550760266", "532", "276070535776689574698523055001401403725922061673898216921889843550760798", "146869525033198853739614265260745546782190536810513851402445396769004461512", "518929578527611982516020780077822187454740717432139505492274142012707", "142"], ["2930719981202524207012025094755172460604583120213953176833026365009973818527998061309394344122050988311163572671474353994083757422286194167744628333596624959201183466292963454653757730919549872851", "304720", "2930719981202524207012025094755172460604583120213953176833026365009973818527998061309394344122050988311163572671474353994083757422286194167744628333596624959201183466292963454653757730919550177571", "893048992672033176360704286873796152195428568391595812044559793945839221981851569242198644540871377158177763864451665149077202561719049086795143145813563557567784625848791823902093055765805237255156720", "9617747378585338038238465131120938765439036230683752877504024563566466981254916189647526726575383920685099674033454824081398521338560626699083185657641851401946650913274361560297183417299651", "220131"], ["121981247499761180018041314923441892567233396653047152341319646282603531890794130069784497466264281", "6356465001609545032623505806629754395393208196362606712193147457486132930724879", "121981247499761180024397779925051437599856902459676906736712854478966138602987277527270630396989160", "775369530584903760129838031465374444566333926667309592789411008643738703888065584805729243055544660827529401037663091338729722102120625763675162151178361597791364815721515746999", "19190107625680915039", "239003970743376463682901498117008229424382778374870228580111748198407183709000"], ["8682", "660542714474913015614528450414205668722196601304858798820358259642779130282602682", "660542714474913015614528450414205668722196601304858798820358259642779130282611364", "5734831847071194801565336006496133615846110892528784091358350410218608409113556485124", "0", "8682"], ["990572871436633253383921435027505132273617170365238620550", "1555615085685192653162082868366956918464757057100661893261247809956610600056994180724117153338694808534871166280144", "1555615085685192653162082868366956918464757057100661893262238382828047233310378102159144658470968425705236404900694", "1540950102277325564506705033386727095679632182095508373379628329778092007291512642940776906549667125391691094963846640802556003335338528725190323337903139816609469415359200", "0", "990572871436633253383921435027505132273617170365238620550"], ["997923495062524232606305255320358486052361256160650", "4240280112765098633908709232157300790637309695435603849304464293572889664446274880425479766441653422345931351543401051760651", "4240280112765098633908709232157300790637309695435603849304464293572889665444198375488003999047958677666289837595762307921301", "4231475150174661602856319932782452797306526566695125925344877725891183089508700234637068448197513276367379752869610494351214213367874454280002482110318677941742076703004583150", "0", "997923495062524232606305255320358486052361256160650"], ["15563138200143831929592062841637995401631681030286340626001037187717023791116239763103360076818402479550491677765878113171532280360148591862134672664", "161046547339873", "15563138200143831929592062841637995401631681030286340626001037187717023791116239763103360076818402479550491677765878113171532280360148752908682012537", "2506389672906449505106633428659050157610690806871781905889794905081268006777067716429943901474486764776345702788695602546472784408986037849153871443471788810331672", "96637515409127956372423911240227730040568716684177830775840635120476936464923907595238765539641266070088392859033020850756908092856197", "73217061429683"], ["575497686183426796686475439668194318191290", "56848087765491474805259129270232225879613552689929439698990751981273248565419752299009", "56848087765491474805259129270232225879613553265427125882417548667748688233614070490299", "32715942972992717039729646157348779170774320441854851542286206335205741380761939296769927568851467567210352029195395248139431610", "0", "575497686183426796686475439668194318191290"], ["4334179101679043974889849560222592132622143948599611191028055543783461061111003943529310374805742317962412889492730749438939493099716737819560172029719016729059959072170492495565576", "343796672897889302274292282864442194974722", "4334179101679043974889849560222592132622143948599611191028055543783461061111003943529310374805742317962412889492730749438939493099716737819903968702616906031334251355034934690540298", "1490076354900817980247197548169245602442035051957488435194541646291662250581329870182663634161631987690450463451749088078298913599367362735711467556725951430439312839200063166791252833078006211620555023355840574576413369872", "12606809324668287500055844071585788772553046323062460617574964438723566842347780973091548723003638045320994475055121458266534302218582271722", "243676437785057539125334804199705370154292"], ["12888309254038", "204678728504234820686444159864354883065605471492247155117", "204678728504234820686444159864354883065605484380556409155", "2637962750685861009325289821120105302229376372903055206466309944612446", "0", "12888309254038"], ["24964029658249007122729244780029166795460508034226339809976263024568864856189", "629059748218730952572360561637026508078330952883272798835780244803683566495289749031680404271609261565016737632769752374922447781803", "629059748218730952572360561637026508078330952883272798860744274461932573618018993811709571067069769599243077442746015399491312637992", "15703866211343052529067729810483600281195725995100344359106758390938644615177057854678131660128621089129882200087834022074286537422497409077176078114542635254985234823134135202164244811081488419695225646128767", "0", "24964029658249007122729244780029166795460508034226339809976263024568864856189"], ["80750713076142932870092538051621978458955422459891071435072772479106904157383462721965583605458557944237105526955809783590600495199310703607487987013104443059234547119040237425482378822760689", "4317167901485250857598710936186980618671268285", "80750713076142932870092538051621978458955422459891071435072772479106904157383462721965583605458557944237105526955809783590600495199310703607487991330272344544485404717751173612462997494028974", "348614386514369591446667107629373153045532020308014020115444347293478307789978722163281843045958821048511636362878127953352852011442524660314128241263593166963337824058100372496013597734270474933780640737675358378181181825400688670448365", "18704556996349846284704368378908588345803454185800273332608373291499352222074162775488960480504795423567194943292971349228863328397280430991429561", "3212599462503232966215943055830555909711987804"], ["54950344193448393126499595206887609049666497217739078269303265154031417978660630248329712074043732932488955343100748003964733434924693455050336509888057660916606664557007806112790172929", "84789628119727505307286781380493354224360536106865723260847567238085866926939923", "54950344193448393126499595206887609049666497217739078269303265154031417978660630248329712074043732932489040132728867731470040721706073948404560870424164526639867512124245891979717112852", "4659219249213516916451985477992568118174147088125899360921469556520375804530078306105652822985461531221326369646820274701635782751378764000338197021858433696321577463441864450535346164333974879646137275931061372034502639440448687907857809922300649679373723963944467", "648078608339401584672654309119275708850184417645116602055186326041529222235373635241539586150564295357453", "15209841258545551129012232177331222591331001510387375099260991096401628048876810"], ["66972796783427054777011809778718885379319665149542127629579179690965094235329972409829055061023580247285880201252198590887007420659320202219326233382991143799818755242948", "9970633587168750", "66972796783427054777011809778718885379319665149542127629579179690965094235329972409829055061023580247285880201252198590887007420659320202219326233382991153770452342411698", "667761217035465016781366061568970299294406700457378308908908097740136335600251464589436838164072696854126091892192983011853376822556238195071906367203163434777399441054089088641723475000", "6717005112856080342912850661638935406419332777724395702772121929358620072190072876724496992898704279677610406811612967433535649032462139504063820066009650", "807565076805448"], ["596927214793198198572506408687608647132669999402023152136996270863993725105935362687496042928920551917796211682776034183889783714356692936384452473477553810542125085581983034617400716339734578886", "838911701347574942676881020709852061913675784078600645128282821275732807042248081446264988957142512519595290890", "596927214793198198572506408687608647132669999402023152136996270863993725105935362688334954630268126860473092703485886245803459498435293581512735294753286617584373167028248023574543228859329869776", "500769225342831206458613231447575445527860886437073427448013507288280869075655712297027755482966226636644766732240788773383724839517172723654866422943935653647254402297056129062449336394672086499617664163609417242792822376971315773532101760901352067204548216734414414638173898832108678446966213662822148540", "711549515681247383683630842998809591914166674737349421714596424743583416473555936922", "98176984137692023983803147566661365517743760622699346522795436236615577198736897119166117023457614666653338306"], ["7597300034022804153744230237708850663273928597350772182041628952915795639549600282745152877690367300690207993901293079943207348282019477650296193708859374274534538401407", "998505874662134214810263855614591059307336895735921514321129673470669516057423313572327744352187907729736", "7597300034022804153744230237708850663273928597350772182041628953914301514211734497555416733304958359997544889637214594264337021752688993707719507281187118626722446131143", "7585948715542602090170893290204255861856751290125372757275170780118588179636475975261204394729236585708844904344383586055230492496639955549296991795164720897253202410297604700251741105453121897220774053116916530292382441711542236532729563748796410155801560212393100038138552", "7608668338174287513400730616264238454830463326480272018540721024", "569260892025661278778670005705712496392236101028934448652377321714064690298218980896640004839246173231743"], ["5127101575815463654648908219122325412734549091120629701748758128690170146338803849441108635790092840941572910820175191598072362302087805219565727730375466818458540554617888677604403233", "53847513653653220808173202346011035665135723639261833288762533300958179791716407831682", "5127101575815463654648908219122325412734549091120629701748758128690170146338803849441108635790092894789086564473395999771274708313123470355289366992208755580991841512797680394012234915", "276081672107390123187172638699285842266715883859200049434970596334565939138141888673911879077841961292828757290740455573616388186661878855689616542679571044426291158422869273781617906996562357621844977762499792144019823645214573283069756626106475690047093177329120627906", "95215196170299341550847580455137193085232785826191102674589403320174021805959534338926041456012814", "9273361727163092538551544724383719106893755054686990445608788220094710232418657230085"], ["1193633701287196459050860567577250379654441284822152138535546457681019751559025782725809696052849", "59009101132223734835659148167181005142455399", "1193633701287196459050860567577250379654441284822152197544647589904754587218173949906814838508248", "70435251794086711868879239617664151345902542927148076355772110230096465149425149028181303367515679269419534944063152667004356782522329381751", "20227959389053904083814381956443417754736180510050404", "23041359913374371843156967907054535884121653"], ["6123903958359993018269436488019490390127562006172", "78473814570073400", "6123903958359993018269436488019568863942132079572", "480566103673280587972714004746774492058987890113154086577293024800", "78037546561364578537931424632093", "9670564556379972"], ["157718415", "66823132460624598699950", "66823132460624756418365", "10539238537024761616967174579250", "0", "157718415"], ["500892752425324876082239377430935277256475613140792024309703081799053945387398030455183283719923189352", "630250542405083632045795658150", "500892752425324876082239377430935277256475613140792024309703081799053946017648572860266915765718847502", "315687928902836273094780327042815745188709465275042569712979530780138260749933527087639573956623673603128447644563949187821912018800", "794751799044678855270687819196092183425450392058095418204252512369660773", "580018716987656116528150439402"], ["88898610408341351877553942630897151001267348857421062729832629613635135993429105045129734735266628757012378131509880433472668233033839681667352", "12867132108093095078528853644454674471877616805941876695083043823", "88898610408341351877553942630897151001267348857421062729832629613635135993429117912261842828361707285866022586184352311089474174910534764711175", "1143870164350028022884870923833080635906959605696308845156195654882567733220813659608812491708851282966994353983967523333106360546025154449117552445214538374125346513778334868507780813660842526696399924366696", "6908968499081968150456991539219440220864954691983387297235737162219763818764132", "3575183124430875994665377306022265008903562368246662847025110716"], ["796829512465365318389437964979514803749235612083046906860078203415834822268273775586279957003689380935816321132355633855257756051744117387512962584", "153867818827838224146295", "796829512465365318389437964979514803749235612083046906860078203415834822268273775586279957003689380935816321132355633855257909919562945225737108879", "122606419060695490660144154130585842092191661403266731029086380222384554406807669988725536972149173366490260252843229841743644318446983723708515661631878087723219677226280", "5178662559433126566696432792112858082619403454991505173249684981287126912266363159420963729657895715398511179831905023926729", "106346732730422856143529"], ["71133853100176568867783005093317534742421088379400777507268927302316778281410376227508255148434658132", "308324724378402989175137633545564398349412772330776396574844505673513484050845071905422415303179027069208963541", "308324724449536842275314202413347403442730307073197484954245283180782411353161850186832791530687282217643621673", "21932325651085747592078132321563891996969318015032879090763827354483106621633661218262108708577962760586751508385675119810337200122191241517312171499963453293193978190592873784753804333700957381937361878387165412", "0", "71133853100176568867783005093317534742421088379400777507268927302316778281410376227508255148434658132"], ["24216854246490938130795171389677524544239367719910317305234087520264636616892674133618754514481354806651505098350676794836011", "173626545959545228965219794464672896924269910501454148828222263357545870255104136663851760945101157130469", "24216854246490938130968797935637069773204587514374990202158357430766090765720896396976300384736458943315356859295777951966480", "4204688756823966914225226218099228145758790356433908563854011318258174313262588029321730469611924542408080920326537631850334411212974690919026895337786051747583353155191778306623970880158820719246379796179462938640072110186519159", "139476680323603484561", "87027555434857831239620119522235085293586506685466244499925049531534265356995776144657065377716690646902"], ["3926769219515983184920125700397845408223104921552896779802140340921482931367621440295149489721", "3749857812982772197398637689894851273156444070899538766138253507129139534785895086414460001504515597514045883486980450805368609539", "3749857812982772197398637689894851277083213290415521951058379207526984943009000007967356781306655938435528814854601891100518099260", "14724826237582272019374430235335900986964725652739117189454648841269641811665412681360726985254539644472711718722960175901034873737037976796745785288451758188410925212602159727657310106885113331673946980832004752747143048619", "0", "3926769219515983184920125700397845408223104921552896779802140340921482931367621440295149489721"], ["731721786033302110375400074403447610742687874415561862678611267894404483938568768766431056287528143744074856122025910765996914463348580523892371407560051481587502058461890368348465607210668673679684773486326432981963", "27153690212946310101524400814316964434777603424368129368260", "731721786033302110375400074403447610742687874415561862678611267894404483938568768766431056287528143744074856122025910765996914463348580523892371407560051481614655748674836678449990008024985638114462376910694562350223", "19868946700012069538168234655795152359315925529022281100021883294939700881714361005559534678436757648798242893392618343922388691319122607084068421176321800779421175394239094245683223359840703227197619145371257835298546729853088712065894827764755131231885506563101267164694380", "26947415997418741502694082606408572340536058228271593088335928776569860469382557584941573358419458008136983874809925636260901763345313120706089248719906235213", "6402435948942543320692198639700793510669508118929776442583"], ["7241497987323362834038782666076549808981561306412603390387937429835690346727569657366368230645598407698646197568259294016502016276361348801671242070310646945216626003232029721", "290507501710413358551143588557431", "7241497987323362834038782666076549808981561306412603390387937429835690346727569657366368230645598407698646197568259294016502016276361348801671532577812357358575177146820587152", "2103709488938296721948621299450716428898527842731778418333701192202219137055368423938325925202331006215097639513974253696282026859070916385297577963717484226969396498266300564274887238245862624562212507406751", "24927060212517012666251218924645608816442268704468598141242278222496017698416907504550251817771410214023586642980539788416021624448775546173416", "242950736109191507060067630575425"], ["60108220245416936617749470651239237873345065107191176812946923164527952359726181452461989285046637652450575599241386314986862567324283174576", "90762280975702821040874497152183903563745665148556213693182788728759817731285093186242", "60108220245416936617749470651239237873345065107191176903709204140230773400600678604645892848792302801006789292424175043746680298609376360818", "5455559174863960779241941081460052673266287639616819876898243699014585592686733933685574775761761989396733184629904399162530121216175426995345693497705503276719114062380446271545616583911095267486540247925253333754542567383392", "662259912369412401899020772768487129170692521785210173", "38838725824406180532579926923233135658364849201971353286839309753858457538152081134710"], ["3194035147404972376726226327589540867861667996913211259379091305010762516456409321924853199791966024048735119596413454179094845307901708299768344367691200078811477282933801013793707055301", "8737499242796485", "3194035147404972376726226327589540867861667996913211259379091305010762516456409321924853199791966024048735119596413454179094845307901708299768344367691200078811477282933809751292949851786", "27907879681916305493057190402310845396599501742023642353132094738106883827451386159279921992916894393651880937196898693540192313175734790744795109823437819742386148515306465377898875440534020345783416985", "365554841110658997537479053430045706891568968912041016824294714568338515997029052332930607542886673145411991068209352123126870250332549676738755766110535382457996842574918", "4045423267492071"], ["73639558097427350759531839768188960313912639161384934654511119258476787963518065127531468367682541674189887250705028370687294269421701509484356956395339792343453789", "34621586584174127016014936178439390139231353720640622590631098368962746357323679903219157071423", "73639558097427350759531839768188960313912639161384934654511119258476822585104649301658484382618720113580026482058749011309884900520070472230714280075243011500525212", "2549518336690401968483033309283652203135267899621690399845015056178056787221390388071338051987594907620505726949542937029982064385096130370893796218137015477873491985772038085858433780918391358596796148341211210352248010860781923189326317603470757582372971747", "2126983924274825931405562454953817894452893923383065785480428917965452", "26775872215633772696639818795391450381347111864461744916681907845465923298538940954620532975593"], ["425013215832503376543330905246988112467854220980951864962796166400423591675778476820405917811007687973363293722096873721348067050678268362017895621924391527273362056525159342568117876302640199735", "56604123625664503724858969132162657146699720753325226201465933613516489073418758995492383336829886725378490112349425838", "425013215832503376543330905246988112467854220980951864962796166400423591675835080944031582314732546942495456379243573442101392276879734295631412110997810286268854439861989229293496366414989625573", "24057500611524251284123615217000599430670220592290665487889252412572219984258995031565221310899813413990077835301032510760180939829028651760585307958545640404273263972303027906409790408323532938412901236915410580873174501080554943291796110891493772479315552921886517073117909322139274162807113978232913724889752930", "7508520379949861590718599170822863917588655604440403538213047435868908734680", "42369272692958207699896495292591395268893921425556430241564063316369167980200494010751433636085012449061699381561537895"], ["6497219141113757085902241569612383595455598050912097145579341223040771568886670006671699794137275660379010843655730570105162881624029358165312486510894762775610699310262694936846349962665426070595143083676755349", "8723661306053575058392", "6497219141113757085902241569612383595455598050912097145579341223040771568886670006671699794137275660379010843655730570105162881624029358165312486510894762775610699310262694936846349962665434794256449137251813741", "56679539218284725329439492503283972542200831341763716447624444973845084326574858668992506135401388676748773114122518226387786729289806902598430046627768487917392117352409891724855894842739747987636341332296124754599402903875773338808", "744781223521959529450212631160560053279578239431733975470855300810678928535141728499639848467188031949759789671043268236113601824504516487520225066336171210634201215531608383532991631048080", "5591110814877517267989"], ["23581761292043764511461913217824993708341113343346121797362449815804181548484514905622604608144232291773583315587715543589232577772122192622828140950803921296595365993282916037289301593797", "674664297906557062135163394486825284624448813796789352192251700150954062314022921005203850214959962776862777061130305", "23581761292043764511461913217824993708341113343346121797362449815804182223148812812179666743307626778598867940036529340378584770023822343576890454973724926500445580953245692900066362724102", "15909772425496730314246910158520342681768732153420161498219592683732629333025009287810080917652905114744572036180814243076794185965230623262600307672957724232479997512817981161654591021779233805371820992096293052847237717888874893031475984672689814836527367729075614690779056201557552910549773934796718085", "34953326217522638201577468669797202726553616740013145523294429199501493", "163708294571235170104938529617341936613054360912191273557329860918330864577790731023510276265367026986644796186548432"], ["4987298038015997120814049089506208689545998833889881056344773082160514140726386662713061393744451013881110254602676958775869046222850679347067096693871366", "310797777725430253850047153335650310402578529948586968", "4987298038015997120814049089506208689545998833889881056344773082160514140726386662713061393744451014191908032328107212625916199558500989749645626642458334", "1550041147069770277331193796838783140898307993603009709692721082526171067865702733452515230814980031552520713266468164943945244443293597898731724974570776660002776971681176612397627587917554784902877255958288", "16046762221131299562890451288694644835892126820452910770472965589425796846595776608516024332927581751", "48644361276480829483639317393627243116245480940650398"], ["278240983524411348361312664848275132683805855026110604661047975265847417742145240835413143902822485740026660061015995631911182777076010017978134369617197847278202799764152664982771874102975509135263838", "5042757843370056891554902320642879117645350479819367503948365470363583024371833111705875082884227721425923246550730", "278240983524411348361312664848275132683805855026110604661047975265847417742145240835418186660665855796918214963336638511028828127555829385482082735087561430302574632875858540065656101824401432381814568", "1403101902014724102373437092074228091616773960607703896286203200305342024127157606522216116358426339674930316723487780673104521822034126728808160112368287808273279370728738691115971115461333397087875907073464661579604824856032388345667866919700194829483031241954874803345142568283610382778361542579127093442001501740", "55176352338676628166522079576540183713735180580137898649638542845090752614521663965209", "1166963730617649144447155574844136909842652526581057184572952824017311916888581226958990523310474635411165161711268"], ["5262910350427", "5793059817271749819738250158350340659558431883798949494947412584269824434958506996825823243045557995446339503152047587613054619701191848460", "5793059817271749819738250158350340659558431883798949494947412584269824434958506996825823243045557995446339503152047587613054624964102198887", "30488354472962237430886108222299379600831493052646939030468161829816451384909243327869324780739659220540246304808355840387201273051490809208174480292420", "0", "5262910350427"], ["4651438292271930996152576253876", "233497173823958527469381466445868808671607863829304170818136656650836602105410237975443806045448318932048115", "233497173823958527469381466445868808671607863829304170818136656650836602105414889413736077976444471508301991", "1086097695462035880767775105691562381556567622692484989954593781736825831470618711882011667425907129289997621136099106535486130386887243740", "0", "4651438292271930996152576253876"], ["7670116901380431282832538685326154309991044605405772886962728414382733246910498994012270779821615209979352235543193", "282377863424458293069194834132605708889843380196616685882852820861823693482233569585907913061394194087043889777947569048720603140061756783", "282377863424458293069202504249507089321126212735302012037162811906429099255120532314322295794641104586037902048727390663930582492297299976", "2165871222827632663265720533510843089733039913248193159381466381555795085167827368964589076684736586348555706680838672100697308473749156062467886121798382401997961903787991163568736101615455764149463722313139021529326778197860979220902771917025857228119", "0", "7670116901380431282832538685326154309991044605405772886962728414382733246910498994012270779821615209979352235543193"], ["8176957856770025843060704492807277113844899798887543680901915010252811475355738109082682795989950664161644035781280930526650345959315", "5556219", "8176957856770025843060704492807277113844899798887543680901915010252811475355738109082682795989950664161644035781280930526650351515534", "45432968605984896219704904456321156438210195315675149063157157316351865922789583840709274722052487689277545662844632950529854658575719229985", "1471676666591080344936134535519078192174372500235779705749884050692172406335268301894270689472454319054314460207792552908128773", "2970028"], ["844135136682763851191130551966114652415046303398609330863621036804825028160791656570994426529295636619290313375429402179594886117967671794864886178119076722953743821388302227694371531457863345659979866", "96825800322389274413411797467435801910271805445967411234194355301316", "844135136682763851191130551966114652415046303398609330863621036804825028160791656570994426529295636619290313375429402179594886117967768620665208567393490134751211257190212499499817498869097540015281182", "81734060189558070324684599058954245182894256290344371844920616799442634838688503861333287574744445688461599833253618534324610874372474735334231803270035446675137764366987109203584896134052674050508230369208224807142345503945602606583978723351205439885511891738923303656", "8718080654868311489195376143170208976643407948617511297501377800467924862773135914611574004728592646289906034930855477446468382855696", "49321292720142198665370783760948707959020884480815359013301033083930"], ["601211069570818015513949207736093593501240633595126670334173086286323499452301852599442476630432977398544377684404993912508037328716954441167322434544928112692642772803957347064528105003747733018314593280193469158", "40784044221341871197571116507906771069176552379635962389162233362787781185", "601211069570818015513949207736093593501240633595126670334173086286323499452301852599442476630432977398544377684404993912508037328716954441208106478766269983890213889311864118133704657383383695407476826642981250343", "24519818847736486184211555928457855179503843945245912405663761238914896632167540448077977408736316429385047237050052843245373620546616279351845347723091106496795304435136619319255112054085652244126903238228247480736011272625126257498843510897112529311239614509659389971009497358550192230", "14741330367041197977607924654619802676258144730926577364083697748050901573256281158712944198684299504154257327728862875468999680523790812770", "23843270350166807801225853134593320417994148860510321860271613364129736708"], ["4332655133527511488451253730551361226498914239800473462816410741475823476601191473715147", "16423031870553529684410420291359281421440576721048137182968539489520023701608451241327832944902551713", "16423031870557862339543947802847732675171128082274636097208339962982840112349927064804434136376266860", "71155333342039679925346747780071837838131455963848041328766753784379771497047624528645912075391608822244424385468140382865200470213894318861501430913042811348735414275183040845368398896811", "0", "4332655133527511488451253730551361226498914239800473462816410741475823476601191473715147"], ["2705773981086556789406621024309382718435853967924238706691089372783838756161000", "996651423820566495098584028362978068515510797544622643914152752965991956790345294205991564950729791307358122529647538187271844482", "996651423820566495098584028362978068515510797544625349688133839522781363411369603588710000804697715546064813619020322026028005482", "2696713490786559382521558464696753220736337221834792064302037608535161473413975632121297278246758958780753386274867026614196903703241720558276533005029310695742838476856344666083794866793956564747111353602000", "0", "2705773981086556789406621024309382718435853967924238706691089372783838756161000"], ["649095449233690967870232459908344192713056576970420536615996338545002108844419235289323715201443958152563644565733434260904290013260010260740937543631724091484629950951574567140072353235", "259009458283178611022492983790686", "649095449233690967870232459908344192713056576970420536615996338545002108844419235289323715201443958152563644565733434260904290013260010260740937543631724350494088234130185589633056143921", "168121860680094760662582039877826473616363290875052778531809183244667701602297906217406320919780442156568902034957492741564785815924998907068734160982967371783535891285567421115447385725494546018599350838800098694969210", "2506068517868663953781126257173467057432440571377145505319817448558654436968169654047351481162192091726798151033017420459803726757876129218506810042807501", "111281371206449089569367297617549"], ["5657499504327822690667396651028562760113508686549328059125299643277386471079944550290076712875296923868372074614728723780192422229793171608255394381238200412221097323691923703543193290", "32124812101317520948407064390820306243596130192619667939745211646074388105012691484439977492362", "5657499504327822690667396651028562760113508686549328059125299643277386471079944550290076745000109025185893023021793114600498665825923364227923334126449846486609202336383408143520685652", "181746108539828314852361030653941259260205825661548336748370880856479445265883529957349818058889382345387963090400183551395350408495906673187817766739677107293864306286973115743133832021246834508113655385927131763667506109184786352683807720964927244294476633865704438088064650980", "176109964051612122077009210951534696616482309597114841645092373083624529923468312893810061", "21933641242267136928870788782100520496924755204389305973311634112425219288154686057472836939208"], ["472560025155858890768301339666011678920801176914784416974486044208989891109636999925917711624121626859012628236577305759992705443811066201283312387185836", "8788129951778753676877709451096147639121945514009680311213445114632240309372052812663931914381981714526058159357628757321978", "472560025155858890768301339674799808872579930591662126425582191848111836623646680237131156738753867168384681049241237674374687158337124360640941144507814", "4152918911085524818226094388924929331992177138552781713480409584402841609845130592286286569947431869517549871361180038687940383959938216472340439541808415332942868450615150666043368211202439372529816434383037351983813451356337946501048595027220285424842364264695612487173103608", "53772534970333568687703040993", "7040478261369282997460079748563936259289609063242180940051815392186949219958121160921415217228196448496532799907426953341682"], ["58738455672892763483008114082784640171919900263030199171609053451786186165795768700", "809491486089951008094114", "58738455672892763483008114082784640171919900263030199171609862943272276116803862814", "47548279773278676332174907387331665667108035016060788739360882733021652698373520480125677841507552575431800", "72562166103332831708770780092475586504459090560391218410736", "672638695665814399760796"], ["616432410183645978225602586092363215050575015806845432226090146217830490666524880145945768562586299548793874456528912672913508609811996259598763511925473307968678699184103109325870855545", "713392827610867322763", "616432410183645978225602586092363215050575015806845432226090146217830490666524880145945768562586299548793874456528912672913508609811996259598763511925473307968678699897495936936738178308", "439758460131893209646770348555807922084389793519743136397431428079688702482570620560763137383234511016998390151341118593959642744048717261681391935338628223599902827486074061450611572717394802975262463270835", "864085516878633224457230013429267439141419736464770092886015285528290714188471807376443914528221308523916127783207492689897406946330950284642624652827046706572392181", "107983774469926339442"], ["52956562536513275654996039717097113854846262266396468260061327542859730473305372284298918874613208534302269229668992381110217175020292534899236360003098715868061598807728824472", "372537926082275824057215458871782761556270", "52956562536513275654996039717097113854846262266396468260061327542859730473305372284298918874613208534302269229668992381110217175020292907437162442278922773083520470590490380742", "19728327979798999805907610041673791540820885730457364997540354782508863327813294291345938772358754561399667018198462739661351869095907518224623140197679140339998704299975445914972820675918598562569856482259840381039440", "142150795473150569418947921426122726734553015206346031950566810358733878980582930383543334721683338306087168812851091106853244980876799", "198698998246908911038261696980233352844742"], ["5730170966128162539069261692827030331654970386709", "9422583581281807836287463862174605920278589393224111021818257005734258946871587524097187386377087931754475947017604872712714", "9422583581281807836287463862174605920278589393224111021818257005734258946877317695063315548916157193447302977349259843099423", "53993014863376938563855120109259610133153428025191996579353981983046539323241503158980188738313422673243447541198675081395963274280746845444407534118656386039943010440918226", "0", "5730170966128162539069261692827030331654970386709"], ["315412619679594723013445215527616037255192160937724549391858390841880698628991683516049717711398321516619066386", "32", "315412619679594723013445215527616037255192160937724549391858390841880698628991683516049717711398321516619066418", "10093203829747031136430246896883713192166149150007185580539468506940182356127733872513590966764746288531810124352", "9856644364987335094170162985238001164224755029303892168495574713808771832155990109876553678481197547394345824", "18"], ["42763941962047163580189074865447360353390011327477342991501740524627211981294585505238198755398129491228606446754699141159563", "7875782589346710957994081326460060391218707830094225554304207707563747508075744337", "42763941962047163580189074865447360353390019203259932338212698518708538441354976723946028849623683795436314010502207216903900", "336799509556524277006952687067623620670228635943601207085749894287792724846359075426478605229790191157198570768836338985774319961652357617351384392700744241892643156473329875303876420213845359700604510644731", "5429802242115268177460209410571215241145789", "2463594675279086860738994556870138266823665402953347017612420348343586004233012670"], ["57003595837287974597827660585875838414019018370316089406360508233732737718543943934254511596432351129994727572530229631881716594837156814503430324140284540718222048384384811265133000096", "52423755596815854571858099034120428087365254188953249225707516411581962238736918182715846104012789992988961688617", "57003595837287974597827660585875838414019018370316089406360508233732737770967699531070366168290450164115155659895483820834965820544673226085392562877202723434068152397174804254094688713", "2988342576313654408062576367930734772379183630210928042309268638121991552791720641959110001365559910298819122692505382596036259300968782603399894768652499024550707549001669149371256486683083397476459912163948884491543737248702333358464253599807230862587859284483980245737666577656615102031383107232", "1087361925682987372660243332765513877460055545162371987259101339016273865", "39524456018248988926902499493170325627711297357385734509707265146928490793725926357838883788045765744091407905391"], ["711599936880503415374481024363571253916963939609455152419816686057362081843242673699036732630519695869297203726389687855107474401338756532298293919574330119292068", "8299988512468857775510806", "711599936880503415374481024363571253916963939609455152419816686057362081843242673699036732630519695869297203726389687855107474401338756540598282432043187894802874", "5906271301581742627844379469750195911260837663973265657072519689284004318243003166730776980652929815590826163389778621953746963333798180366637971467716730512884565663451664848543804086808", "85735050815008389515955305442978900714945519324134891841725579960019699687567323195627321802696064496361381010140514907454533179986340845", "3632630705059907422620998"], ["72510520421833878379384212095821729724665089834103062473093162", "894784959097647389872975157500252746395978333036977617906792974764", "894857469618069223751354541712348568125702998126811720969266067926", "64881323049799752628031428466573293431758652550086218200868603741890437663682758356456895089830255699403669025493637078486963768", "0", "72510520421833878379384212095821729724665089834103062473093162"], ["6358961291112494036856694976109954872746258569743133301580566460904246552327900931642518929399864342949218", "6407102873194930572019047633080188400335573166147220556707250753326450802371119177006045626045933575526406303988538165417694348017658026619", "6407102873194930572019047633080194759296864278641257413402226863281323548629688920139347206612394479772958631889469807936623747882000975837", "40742519158822205871663438411114054744654419210629918337385242836448977454196466818052428148020341259849965357161369435697446897001143062249527080588102104535254500788891334293256731566136606753334592396637977309677516569146195882650236409233942", "0", "6358961291112494036856694976109954872746258569743133301580566460904246552327900931642518929399864342949218"], ["635708592894565255", "712403310533142616689799263064579", "712403310533143252398392157629834", "452880906112454111340992901135898654824945194602645", "0", "635708592894565255"], ["795198629351848023582353730916115767641152234210089804517856875189152607911393212044747005807197294873665545963002682299185272806920508581987168650488226411279511624489985747908406169385365857726315773172360248", "30437808041502049522503692055648745668725297282842037352079563724141595309664051193809660144922733089744358645952305584267184934992752", "795198629351848023582353730916115767641152234210089804517856875189152607911423649852788507856719798565721194708671407596468114844272588145711310245797890462473321284634908480998150528031318163310582958107353000", "24204103235077087482566609718908361542650292290929967231214773619378861612540270822912087678419381624063505008545477163647267070446916939910065939162107806556648876922208764960039449902899800669931988918720181453107837044889998048710278775469980948329084336131292309044894299609086355460388547467998428634259390924579814537756311934510612922496", "26125357918927411771501229366360488704369171450768826291505044255071087483953", "22829345596401201976535110575107371425362062780880406472657701969246382174842671089744895756524862541481069276950195155775167201051592"], ["51175569289845693801144485233537397284414", "93911613368602671372560181298228449682975426047510511172906007366869720824", "93911613368602671372560181298228500858544715893204312317391240904267005238", "4805980277066125175218255139951142624382418293564158983072702568763230749092713487622399994489723458594539906437136", "0", "51175569289845693801144485233537397284414"], ["44909457", "2875018409994095941812", "2875018409994140851269", "129115515657838221952680516084", "0", "44909457"], ["50001865542909522870416287924074852562866", "40299387852274861405217768322992830318045346489995", "40299387902276726948127291193409118242120199052861", "2015044572851008993725804345400231059407487585799360401485815079938479465392761103177525670", "0", "50001865542909522870416287924074852562866"], ["67720479716563363085790541580951459230367478872605671507111635238540009566152349973900605900791431016", "406516584340371123344631", "67720479716563363085790541580951459230367478872605671507111635238540009566152756490484946271914775647", "27529498104268722335751240142364567040449980298297605592665494622214964785835201235317863652818195877784115019888602630475096", "166587249635704588603925933394091688512854597186568751702225747380433795200025", "269614449807749136615241"], ["14383150021924289930687432189138687494212680958649841721111656387645912", "374626406661618363069342565557680250834912270946158237375798", "14383150022298916337349050552208030059770361209484753992057814625021710", "5388307809188474114121749167585776292785937966093976899655076796325596150659742091694310550364530295782192051135402925341702437776", "38393316024", "29237286084592443767731823564304287898475024831835324458760"], ["856133512256923380775737430371177194173140663380083131234738371558490270056231128137378489177249225570878703457264715336921018431368759488335844495366570656845968780888", "94410753675196403999706215736510548891475887743425662932869202361624568520139431875267080078605604495218980225928978", "856133512256923380775737430371177194173140663380083225645492046754894269762446864647927380653136968996541636326467076961489538570800634755415923100971065875826194709866", "80828210138769134661856167181581514634445187971454713254411726353256243727218255467917276159464339324294358830363324356621474972913395021803275394205114539458401856765642098248509969298245539700742679036347747084733117423900768959338391155771367998621792413130617001197284325931772464", "9068177923907907563491170378760816081226284220708260", "66588980093213630716741798095997637262707289709386026777715393207683334960410034126153312054759667795159902350822608"], ["3348198324653634014170516451097357531894819580126169824841946572579440115553454419799859900313446119164821171654171212460359269092134267604514971464095408064612210731582460077740274817092229", "3297184649303031390292170016952096868507676105973564407029076555452", "3348198324653634014170516451097357531894819580126169824841946572579440115553454419799859900313446119164821171654171212460362566276783570635905263634112360161480718407688433642147303893647681", "11039628118870089506880980456098572340245742715876452746451199275404412810905570772469193213074898909138163383405789135151619697534013798472314273427956000570806197361248674426114498999122634910850431169810251995265006880209293684968465722266104353916782508", "1015471889134685267001380012297439696266353682769163565751263058564562375352307963283885612169215494087140509676583015281433", "3262518592959541772694842974318355412202264650494692797324806569513"], ["498807049577358786076628538689983969101638943776065683940770108179348433201515758664777119850876274210855061672442305810821939466748781865509815703641112787399838990", "2906557", "498807049577358786076628538689983969101638943776065683940770108179348433201515758664777119850876274210855061672442305810821939466748781865509815703641112787402745547", "1449811121598419221182527215529143735280152383504930146117832943319442443960898038957418591142403390941480255489468891050585183910654939172670613402128001860006513815257430", "171614404801749556632341474359520205212434830549019229260176252583158848493773133871029234881984517837033666180447280342625979627011884461756578557943681402910", "1958120"], ["3", "617378487279522374207080302594002001017016219642896828", "617378487279522374207080302594002001017016219642896831", "1852135461838567122621240907782006003051048658928690484", "0", "3"], ["639648318589585129553237471489155477828473442204329048196532005678624", "990773421495558769085975982543350080025686598021578767434616039071", "640639092011080688322323447471698827908499128802350626963966621717695", "633746553162884487186358306947749820084728538417542475725334200252196613416325644950099970017264418029647800216057900443330842253518304", "645", "599461724949723492782962748694676211905586480410743201204660477829"], ["415505475441665397501561743379883648371903391814963982697497331266504284971934459974385919350100022452684638434094175384353268126179927502229365866788992498", "42125865877869801263103177152588650911352172886570051973882729486285245639851", "415505475441665397501561743379883648371903391814963982697497331266504284971934502100251797219901285555861791022745086736526154696231901384958852152034632349", "17503527929976121060028127617066591334686249667447997637827925462232931675872262006933529355379350463251887463346953526191223554939929910243208142146627183695994721085836998776864211178164700997990278786589898067851601423895648837798", "9863428722065628456270862263359588218099877636223997024998457730459977354726841", "2671013806845272728666262195429065477568964717666549736942799611706420051807"], ["1793790506652324348638315105311169622231234606706133459737472993969640078779026068643676749261220828532992223386072027975203599474725080239898567726725014147606357779881979623834156801944385703162140130846739822213601", "80553136", "1793790506652324348638315105311169622231234606706133459737472993969640078779026068643676749261220828532992223386072027975203599474725080239898567726725014147606357779881979623834156801944385703162140130846739902766737", "144495450637873587971973611488984968898661264721905680616383186379563597136937600854999428723277020926850803057360640575282380176177057951175461952296090899234059012707491168587941674312351165983275504011155228055388022402736", "22268413071495122780053095702086255490180228448289504951582182895643443090521343186982524792842588133787767410893500508474351631384345858861392655485504799559961983104940565241732572670347504573405312623045983", "19360913"], ["73457366047", "64920335619512895932399", "64920335619586353298446", "4768876857496651312343250709856753", "0", "73457366047"], ["7197135249002451820814937351668114590820127432770560179650233707133681234888398609421561688293373299949717130899545324676212", "28895132733", "7197135249002451820814937351668114590820127432770560179650233707133681234888398609421561688293373299949717130899574219808945", "207962178317278851204885147005529670065601565497879870325757828482098368257011628261048649335384593746365298723146297845868725987647396", "249077770831032915913580529309005634835618577491258488750207524687257550480427433495311699431928451351119015152078", "13333907038"], ["528371359119469934032579744357480523708974588", "46996969915513220835125587074710822441555188709418852416415436", "46996969915513221363496946194180756474134933066899376125390024", "24831852868756560570659920713061294336535615373473772061414840219185489608851310684930870457913966174940368", "0", "528371359119469934032579744357480523708974588"], ["20772316111730402244463936785324326801793777984816272", "190568190103482615458111247825599527550091150372526303525904082877041091089121520063190062686574425265408662045579598323411", "190568190103482615458111247825599527550091150372526303525904082877041111861437631793592307150511210589735463839357583139683", "3958542685669874124063955806885293241315123421999294100707087994301951339401365385707687707084050746352105588232412971360684450039183271763401868843655002092167313466071343792", "0", "20772316111730402244463936785324326801793777984816272"], ["987655909572424975423948787572201107760084609031897761267014750668625818878840630460344991630485504208962579060826248541605", "8705152219196900588886278831967002834017494343491692927410797259863400258364009013868", "987655909572424975423948787572201107768789761251094661855901029500592821712858124803836684557896301468825979319190257555473", "8597695033017328646234632086044523742131414276588341226972584181312475286976515707322960121664110588585395619877183002554288961017977617842310909826202410071892055817888579410615093955934229055009509219978140", "113456477807982754141727887177464451647", "3490665620456218377649927517033432636432354304879092606661108377050257178176410101009"], ["1177463662180873676241773804280830582864450178709243304074662921183380345709334538624605260510277186181676510057099639357224361003", "543870029253229293255734459942040423199368357250960103213870029932936444478", "1177463662180873676241773804280830582864450178709243304618532950436609638965068998566645683709645543432636613270969669290160805481", "640387196394926260551321642851873787134310037281389933826301594642966931970426350543618131715725772644485200064272823229200019039718478262819158011998961196149935105997269273483325059123047764064337891434", "2164972509696134069732546437878341756072724287876153500", "383145944932831135907595633399429614965047823187738550677274971064268988003"], ["360835158428259865408446236222810857007188467953102912317116224585514795541633477884571224988330250569570609092193734031525028069016558856390098950024658287599870688723324886003231", "841016111839043102552115962683466945455523262479075997985742615275122740768208531854705960917065434747249792698848823835945872972439231301", "360835158428259865408446236222810857007189308969214751360218776701477479008578933407833704064328236312185884214934502240056882774977475921824846199817357136423706634596297325234532", "303468181956160235340726332940760950609272126083210169585133854286228656212101753346897510296268218175061780603309659611507908753164540397827594420725849503989016942587203300039525368328027800204875969891743512861908865381015509804852525034821849713183802524480682396938823277093655468796779925496034326297407842333531", "429046665514201094817993340211316146067487", "351808825432456550609951306097277912326780863176486514788131117239425651237147564318163568956492474857660077891519304433641702432537192644"], ["108150411205932577342455", "5854855779930546778769424413239804215351233491354195811092489761018030351118977212291516685627527139225151814749006170653432178", "5854855779930546778769424413239804215351233491354195811092489761018030351118977212291516685627527139225259965160212103230774633", "633205060150919726308106339812470522798437449925700849115514555089974489204227410188537176187892300565921262797148982088543642242759128481383822516990", "0", "108150411205932577342455"], ["5689909077815799646223769693552", "2077556130691444490446483948546528302795971472520938819811203253121171647464167669457027712731152420814411740", "2077556130691444490446483948546528302795971472520938819811203253121171647464173359366105528530798644584105292", "11821105487693117848861193050806487729580571069302023775044262634201865207124205378247292493613468617415854051424425575359687901324951100480", "0", "5689909077815799646223769693552"], ["69031091727342247692", "86978596049312425428521375272173", "86978596049381456520248717519865", "6004227442195534078788383834183397505272338081074716", "0", "69031091727342247692"], ["659559203198944991896103592402827072002023929375137002381150157283447072718676180819795812759769942167363029380357216070161107896852486720", "23482024820247293", "659559203198944991896103592402827072002023929375137002381150157283447072718676180819795812759769942167363029380357216070184589921672734013", "15487785579940154071555680121975311888595525314937490684381532848206649702581394432507072811340460245388785038168331073850182674066226443892896732398448960", "28087833491694566196631844291030921128707077986831616122299652966541546506960093663654092429215136596907196804755708654034", "7473312790456758"], ["3870220925449684232910773606364830858414598296888729420099465617318063702072484362308605623074445383187453081528925645029540341110492048558735821576", "21906433007120857776311337476186859446767923272347570826137833173729398433789823262322400331687676874053128439995781331183983890", "3870220925449684232932680039371951716190909634364916279546233540590411272898622195482335021508235206449775481860613321903593469550487829889919805466", "84782735426120795292447502067881894300321057126002458380894858498162898976573989946604470599260030418636677040635021580651854615200802983607744622229623567024780193930826408105677886863227358064033039786524733862137425145148561434843068773537054485885234858232907591898410640", "176670520672700963316", "16186218790544417423924412781505653511879119326582213726982805126414995585346561764814219186407052494335287129014454925110842336"], ["748248664439843674544519482920509248044070832118031748222419481542256415605079329105061073899239146668202921000838862683465227101815141930826841827570436463881113501", "878884758858545787902590650129658907382436393849626092685261927100445803296237557554", "748248664439843674544519482920509248044070832118031748222419481542256415605079329983945832757784934570793571130497770065901620951441234616088768928016239760118671055", "657624347012440952618457516187080742091960550474055192737748059375502466698425554879691850282062811512531096118665374885608033763701856510557285879054501664654101530626240596477555292109232212414799143305286835859601100978947085099967905966093936554", "851361520265334749767466400061620447218919601019882784690413526722875299520566157", "366727901180609825167442609504615873979610969150480021930185631622992659922929013523"], ["104773428171647", "3861828766902373963335155677304202715892369394300130", "3861828766902373963335155677304202715997142822471777", "404617038920245983829062356909412583893188104057885810369074414110", "0", "104773428171647"], ["2725706397599128082282326459931061221908960980353600006456995", "73202967224532681756061873934591406436259653889911923448833100019", "73205692930930280884144156261051337497481562850892277048839557014", "199529796087148019368673306871100912589695325488842223222457270547052445841099688933469785919010837649107482936216482657182905", "0", "2725706397599128082282326459931061221908960980353600006456995"], ["660768627352108206512337720151773660367744237772693025776767481704946682990927401414629912179923922761078224343423534145155515909928744649646904706143", "3093389475501727071262747", "660768627352108206512337720151773660367744237772693025776767481704946682990927401414629912179923922761078224343423534145155519003318220151373975968890", "2044014717592734153270070671822374748194868927645921221579220758275503947487933655008849432158771693296342539140919627227339003264647495862199922694871034597815018367977954821", "213606670800784294117789509783070212878121897066011740134270038397723210465607843377083114407217086436291323207348855623730281", "1119678907900941693564236"], ["56006618975697811415524830226793050383780321242989841090948032569246063337578669201530501854606253970119523967343728525878066003868311", "68700031573294800558246511983266818906629082281336864224214276894772269707278902871236396890092851008082985440403563557", "56006618975697880115556403521593608630292304509808747720030313906110287551855563973800209133509125206516414060194736608863506407431868", "3847656491943931346493091064910591122856290059441771470940007753882173301574812271655709744110242470834723022277843674096255803605841932345582917003746743441113666965407229598839560813950895144863499657233241878103581953871024194833260355193711346742227", "815234253800092", "64272098168472010408507032368928645971043118907662121183208358489342002350693446614217316525021067321383965780109421067"], ["9903000367919865367858380209022192727500514784145320955801683599107079403774009845292415396022967723307213", "44227256165629723162311455097906756900024594", "9903000367919865367858380209022192727500514784145320955801683643334335569403733007603870493929724623331807", "437982534080317282524642539877613965553519687110988951982191234367077782839063125733821565452477687457136929011838979270403203391550556075706717596522", "223911705732624052791403371512086474591238075074977071083203923", "10599311844471599760618790247649428706024951"], ["5412489034475119084864692899333284492620380861152857821206633584926769638638364616961917760192989557179710404825973036743893311824007379949573689025706631969016893502381483854463210387", "4434675837967464054722827930122276186569648372265150627094155408400067290949255051898502287912403242780790", "5412489034475119084864692899333284492620380861152857821206633584926769638638369051637755727657044280007640527102159606392265576974634474104982089092997581224068792004669396257705991177", "24002634344450659170783148732673923466726297071553247000680744936005508238410597115121111584236872210708768991498855478087171653978609338011661452480299988231687602989388468280998785317284693305871258750889460435060285467061486420619852488287562915289634132654485294388983174553204692065730", "1220492597933790389763830191535167233882186895031881321675469677027220899614544", "222102193019182126322358431758248834657901277806994536952582173829272081425006088450855703181692775400627"], ["48315361763470027881176925", "145424529424516514787578392380660879398123645328", "145424529424516514787626707742424349426004822253", "7026238748427907196766346008357136414412918513021669831741028415917656400", "0", "48315361763470027881176925"], ["4872841577815701156247262116714327655828770003573262941583432738092573413889301161526280059095469441954181516547372383916057382569499750473291997656530849684108234796687674600274218426764660", "30524209138755951040474969328333867936699130594710148663380259382708898744248096015734983353319487", "4872841577815701156247262116714327655828770003573262941583432738092573413889301161526280059125993651092937467587847353244391250506198881068002146319911109066817133540935770616009201780084147", "148739635421271992974219314599179491911336106933767185068542208999587352642879851348456200216287008721714020353898879895423715061899129859740878459984496028181004352039640624702581272946435601573097562662157171464653591023191651787408374514358697436107462938478756362605583971216740929420", "159638585742382296255624469504185859003552772874560873562260040446591130275898682995657748585", "4170090824199168023044996164092713227390647566084583441278186100963118273988626795606205799588765"], ["64611441875981955101532505325644433299186054343538126943403822741807090073678671399308759780160926179401333752973573704330535753501526124359482524491889716599194754133765511075201858288771222305201888357", "264354674645460452617022000043242095431", "64611441875981955101532505325644433299186054343538126943403822741807090073678671399308759780160926179401333752973573704330535753501526124359482524491889716599194754398120185720662310905793222348443983788", "17080336695499288688257984121438946821097447840282992836141226646842909012191186073547694331598849329458512650880198271734993499929021356752990582330422179744975836002536976701260967468567299286033464348851786731074620472460909864054801796867", "244411951340129156802891190745178021330634427294800814645545567584590512936619026774266015288659559388651243518968174593419815793015278716948196029573982274695658876", "209396125643031635504407084707787692801"], ["37546175610936508962727684836962700876889077861317429976348474354078122029272684785234142007524683728428553098765212682517246380437344539037721905365610829043721176515478", "682620043857564460352060357504576796141710036405701766959190081656229781797433742061305670905568130664318975445096647924375025176", "37546175610936508962727684836962700876889760481361287540808826414435626606068826495270547709291642918510209328547010116259307686108250107168386224341055925691645551540654", "25629772042221296844483515032120583483130231235597438991816777780673010842391407868953490986862436815789023193350119515614658185263516191007738711072014984411242148968693467756120529970067227629652595292291006882541314807861380341051469995261561630963363178271400884970128246892395948485316203674128", "55003037119681906435705589823215302318707", "424839026572271524035208904650156271884433125743378093664157415234707540437344222019387119657794361679500734225283491486875748046"], ["565394924778947658220641471810130922255682798857451018638601615363569867076779464910321264226657882538471736409256608567734262633757610745789057511320391526119739726120299582602889627317436519347834773933686892611", "2258605661202837940765952558923114314239823694169567978657", "565394924778947658220641471810130922255682798857451018638601615363569867076779464910321264226657882538471736409256608567734262633757610745789057511320391528378345387323137523368842186240550833587658468103254871268", "1277004177921083896741516403079609291402576118739726873412456975996345403732222958364442846840125571277972352597230920355572598206893410622998048003448123515399269315540230558725108165893447706840751190695649594185365136960203617343597172564552649984901163973582699003427", "250329189592946566554274862582274405864443381910540795824902176560861410506090484810183725882826911151278283324713591571885312485296091492933972961429924902", "341536501485557994227293164030597985773642195950238075997"], ["4610940106218404547421992617805601682279646599569037122567922611104020323853361866764164016411009939485170010866248685737776536634161382223503680505906413885103443577359594174939164945570836268665807733141", "51826662463855845621301877524788972150797462986081411943691919676", "4610940106218404547421992617805601682279646599569037122567922611104020323853361866764164016411009939485170010866248685737776536634161382223555507168370269730724745454884383147089962408556917680609499652817", "238969636526036872737616123813621693659982972305545688533881601813695500025661168498874701190949293676399786500971527647993954375626145919055831174961537394716586427193636642130097662631789512482455595969411580798647134039534555008946019647739397110309728941956215182316", "88968493956833425803524410496156077888583704369019732228406958079981058654920899978605262058340387553806874086299598246425608942299935524567", "33605902173095081953495577851666388312700631220238482005519052849"], ["78807503876898930741613735438959406161760887741647179674239317317365824638595245243936161327496142186530289027", "93809164728452520538147207637591983315822128179588830247950353004276553958755997221654724701860872307113050147957054585393917970585", "93809164728452520538226015141468882246563741915027789654112113892018201138430236538972090526499467552356986309284550727580448259612", "7392866113026172441811518568721813466021724375541519615686054335414330767014272425919759915418921672997105451636869771509505549622576173181020082532882659785592748045825930463538846959468283471632640900672001280308015213200154771149334270795", "0", "78807503876898930741613735438959406161760887741647179674239317317365824638595245243936161327496142186530289027"], ["71599946743965115997179427251754921120091166462983609223208181545049231655826689047530427", "1366422762554", "71599946743965115997179427251754921120091166462983609223208181545049231655828055470292981", "97835797028608091128672971457358431361479331670682340295997717437440931121089812178969661072711230558", "52399556496070548990427563670121334561641287351325852716272051636266957216667", "840175242909"], ["373102284099207894805220953052451251", "8376770672640209376369109", "373102284107584665477861162428820360", "3125392271337320212260280051418761191826006083433366604805359", "44540109629", "2820898308227116223400690"], ["684864984739125304592405309731320280847032938228529467574794339504823315649112832073408262323", "7820698849218719074986723902046756817777258203727315180148216464463", "684864984739125304592405317552019130065752013215253369621551157282081519376428012221624726786", "5356122798019472870845536888264626136355693494917802417499738984492235978198059585258943922509501336565614505499408940140624094230308852946425565459887511327549", "87570816616668817672584885", "6113579887882665653395178650856276415469778020242049628096454820568"], ["0", "6652797", "6652797", "0", "0", "0"], ["198975085982777741722949731456372827465937519564811837289080574188109836208137989232954", "220042785265566544956912288461731645616593232611721202259548623220970187772209345251859364424872547641537486662901178596227", "220042785265566544956912288461731645815568318594498943982498354677343015238146864816671201713953121829647322871039167829181", "43783032118106002441679390588800419937638392474012600661631073123789107242580050528982876185647490770228819513583022852201941582861714361920776581913489383568100154006433784531408189658267075590011926208464558", "0", "198975085982777741722949731456372827465937519564811837289080574188109836208137989232954"], ["499893839215625559841907790879736659306171713260412453446313033450348947671077063522088619160231690502279630366877899344510706865162", "8125532184612606090573573356774549963985099719837353157", "499893839215625559841907790879736659306171713260412453446313033450348947671085189054273231766322264075636404916841884444230544218319", "4061903479436124812732138535262277563707052389429689246912797517817968427187372399862811679088452268758322203841324155067015813738608352331472537341337749815273131864022728103322974016434", "61521365968161328785330228454072320292263205818635290475982241069345022078566", "5091933200531170327715091518348974824626661834764732300"], ["409546468613011125613146902084454925483123556979331339071030273881135", "8402786458586669452915436579075232013233767123190056940706588604081244447997631017173557232221046330408849904847276903", "8402786458586669452915436579075232013233767123190466487175201615206857594899715472099040355778025661747920935121158038", "3441331520623400331590131990932714662269149683198826541138265337343297616178359294779637749128759020160980798997387940419993084345647971262282224840518393065813816620891179634289852924905", "0", "409546468613011125613146902084454925483123556979331339071030273881135"], ["67420657808131170520469073243534996552606042265182636729833976077", "411907770729721139696", "67420657808131170520469073243534996552606042677090407459555115773", "27771092858878677571379654361770376970734899606206240718751024690195217757771639052592", "163679014087768079286354104594258537554307636", "344243332093718457421"]] \ No newline at end of file diff --git a/tests/fixtures/civilization_benchmark.gd b/tests/fixtures/civilization_benchmark.gd new file mode 100644 index 0000000..3227ece --- /dev/null +++ b/tests/fixtures/civilization_benchmark.gd @@ -0,0 +1,30 @@ +extends RefCounted +const E = preload("res://world/owniverse/math/exact.gd") + +static func seed(world, global, fragmented: bool = false, large: bool = false, stable: bool = false): + for id in world.catalog.entities: + world.state.amount[id] = 0 + world.state.stats.total_amount[id] = 0 + var entity = world.catalog.entities[id] + if entity.group_as != "": + world.state.amount[entity.group_as] = 0 + world.state.stats.total_amount[entity.group_as] = 0 + for id in ["RD", "BG", "TWD", "SNS", "MGT", "BH25", "SMBH", "SCD", "GEM", "LGG", "LSC", "LGF", "LGW", "LUB"]: + world.state.amount[id] = E.of("1e48") + world.state.amount.S = E.of("1e50") + world.state.amount.H = E.of("1e48") + world.state.binds.RD = {"HP": E.of("1e30"), "RP": E.of("1e30"), "GG": E.of("1e30"), "AB": E.of("1e30")} + var count = E.of("6e20") if large else 6000 + for id in global.CivilizationRules: + if E.le(global.CivilizationRules[id].span, 0): continue + world.state.amount[id] = count + world.state.ethics[id] = {} + for ethic in ["m", "l", "w", "d", "c", "b"]: + world.state.ethics[id][ethic] = E.divide(count, 6) + world.state.batches[id] = [] + var parties: int = 10 if fragmented else 1 + for i in parties: + var lifespan = E.of(global.CivilizationRules[id].span) if stable else 1 + world.state.batches[id].append({"amount": E.divide(count, parties), "created_from": i * 100, "created_to": 1000 + i * 100, "start_year": E.add(lifespan, i * 100), "end_year": E.add(lifespan, 1000 + i * 100)}) + world.ledger.refresh_groups(world.state) + world.speed = 6 diff --git a/tests/fixtures/civilization_benchmark.gd.uid b/tests/fixtures/civilization_benchmark.gd.uid new file mode 100644 index 0000000..ece0444 --- /dev/null +++ b/tests/fixtures/civilization_benchmark.gd.uid @@ -0,0 +1 @@ +uid://bjloakx4qdpsj diff --git a/tests/fixtures/legacy_quantity_math.gd b/tests/fixtures/legacy_quantity_math.gd new file mode 100644 index 0000000..f9576ea --- /dev/null +++ b/tests/fixtures/legacy_quantity_math.gd @@ -0,0 +1,59 @@ +extends RefCounted +const E = preload("res://world/owniverse/math/exact.gd") +# Frozen apportionment before the civilization performance refactor. + +static func allocate_whole(requests: Dictionary, limit: Variant) -> Dictionary: + var total: Variant = 0 + for amount in requests.values(): + total = E.add(total, E.floor_value(E.maximum(0, amount))) + var available: Variant = E.floor_value(E.minimum(E.maximum(0, limit), total)) + var result: Dictionary = {} + var order: Array = [] + var assigned: Variant = 0 + for id in requests: + var expected: Variant = (E.mul_div(E.floor_value(E.maximum(0, requests[id])), available, total) if E.gt(total, 0) else 0) + result[id] = E.floor_value(expected) + assigned = E.add(assigned, result[id]) + order.append({"id": id, "rest": E.subtract(expected, result[id])}) + order.sort_custom(func ( a : Dictionary , b : Dictionary ) -> bool : return (E.gt(a.rest, b.rest) if E.ne(a.rest, b.rest) else E.lt(str(a.id), str(b.id)))) + for item : Dictionary in order: + if E.ge(assigned, available): + break + if E.lt(result[item.id], E.floor_value(requests[item.id])): + result[item.id] = E.add(result[item.id], 1) + assigned = E.add(assigned, 1) + return result + + +static func sum(pop: Dictionary) -> Variant: + var result: Variant = 0 + for n in pop.values(): result = E.add(result, n) + return result + + +static func split(remainders: Dictionary, key: String, count: Variant, weights: Dictionary) -> Dictionary: + var result: Dictionary = {} + var sum_weights: Variant = sum(weights) + if (E.le(count, 0) or E.le(sum_weights, 0)): return result + var expected: Dictionary = {} + var positive_sum: Variant = 0 + for id in weights: + expected[id] = E.add(E.mul_div(count, weights[id], sum_weights), remainders.get(E.add(E.add(key, ":"), id), 0)) + positive_sum = E.add(positive_sum, E.maximum(0, expected[id])) + var order: Array = [] + var assigned: Variant = 0 + for id in weights: + var normalized: Variant = (E.mul_div(E.maximum(0, expected[id]), count, positive_sum) if E.gt(positive_sum, 0) else 0) + result[id] = E.floor_value(normalized) + assigned = E.add(assigned, result[id]) + order.append({"id": id, "rest": E.subtract(normalized, result[id])}) + order.sort_custom(func ( a , b ) : return (E.gt(a.rest, b.rest) if E.ne(a.rest, b.rest) else E.lt(str(a.id), str(b.id)))) + for entry in order: + if E.ge(assigned, count): break + result[entry.id] = E.add(result[entry.id], 1) + assigned = E.add(assigned, 1) + for id in weights: + remainders[E.add(E.add(key, ":"), id)] = E.clamp_value(E.subtract(expected[id], result[id]), E.neg(1), 1) + return result + + diff --git a/tests/fixtures/legacy_quantity_math.gd.uid b/tests/fixtures/legacy_quantity_math.gd.uid new file mode 100644 index 0000000..caa1c75 --- /dev/null +++ b/tests/fixtures/legacy_quantity_math.gd.uid @@ -0,0 +1 @@ +uid://dxsly3qpyqrjy diff --git a/tests/test_async_save.gd b/tests/test_async_save.gd index e3eb626..51687fd 100644 --- a/tests/test_async_save.gd +++ b/tests/test_async_save.gd @@ -58,6 +58,19 @@ func run() -> void: check(E.eq(completions.size(), 2), "Repeated requests coalesce behind active write") check(E.eq(manager.load_data("latest", "test-password").state.energy, 3), "Last queued snapshot wins") + var pending_clock: Dictionary = preload("res://world/owniverse/simulation_time.gd").advance(world.state.time, 0.01, 1) + data.simulation = {"requested_clock": pending_clock, "active_clock": pending_clock, "speed": 1, "productions": [{"id": "H", "amount": 7, "resource": true}]} + manager.request_save("checkpoint", "test-password", data) + manager.flush_saves() + check(E.eq(manager.load_data("checkpoint", "test-password").simulation, data.simulation), "Encrypted save preserves requested time and queued production") + var malformed: Dictionary = manager._snapshot("probe", "test-password", data).payload + malformed.simulation.productions[0].id = "missing-entity" + check(manager.validate_data(malformed).contains("queued production"), "Unknown queued production is rejected before resume") + malformed = manager._snapshot("probe", "test-password", data).payload + malformed.simulation.requested_clock.year = -1 + check(manager.validate_data(malformed).contains("simulation clock"), "Invalid requested clock is rejected before resume") + data.erase("simulation") + var incompatible_path: String = directory.path_join("incompatible.adventure") var incompatible = FileAccess.open_encrypted_with_pass(incompatible_path, FileAccess.WRITE, "test-password") incompatible.store_var({"format_version": E.neg(1), "state": {"unknown": true}}, false) diff --git a/tests/test_civilization_evolution.gd b/tests/test_civilization_evolution.gd index 855153d..f36274e 100644 --- a/tests/test_civilization_evolution.gd +++ b/tests/test_civilization_evolution.gd @@ -53,7 +53,7 @@ func invariants(world) -> void: check(E.eq(sum_ethics(world, id), physical.get(id, 0)), E.add("Ethics equal physical population for ", id)) for n in world.state.ethics[id].values(): if (E.lt(n, 0) or E.ne(n, E.floor_value(n))): check(false, "Invalid ethic amount") - check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Civilization state validates") + check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Civilization state validates") func run() -> void: var global: Node = root.get_node("Global") diff --git a/tests/test_civilization_state.gd b/tests/test_civilization_state.gd index 30d0f4d..361d349 100644 --- a/tests/test_civilization_state.gd +++ b/tests/test_civilization_state.gd @@ -59,7 +59,7 @@ func run() -> void: world.state.amount["C0.2"] = 3 world.evolution.initialize_life_batches() check(E.eq(world.state.ethics["C0.2"].m, 3), "Losses reduce ethics without inventing population") - check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Ethics state validates") + check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Ethics state validates") var restored = fixture() restored.state = E.decode(bytes_to_var(var_to_bytes(E.encode(world.state)))) restored.evolution.initialize_life_batches() @@ -117,7 +117,7 @@ func run() -> void: world.evolution.initialize_life_batches() check(E.eq(world.state.amount["C4.2"], 2), "SMBH capacity uses stellar mass equivalent") check(E.eq(world.ledger.physical_amounts(world.state)["C1.9"], 1), "Unsupported civilization degrades through missing habitat families") - check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Capacity-limited state validates") + check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Capacity-limited state validates") dispose(world) world = fixture() diff --git a/tests/test_descriptions.gd b/tests/test_descriptions.gd index dad6dcd..8a225d3 100644 --- a/tests/test_descriptions.gd +++ b/tests/test_descriptions.gd @@ -47,7 +47,7 @@ func run() -> void: var text: String = description.render(world, global, "RD") check((text.contains("[b]") and (not text.contains("%value"))), E.add("Localized template resolved: ", locale)) check(text.contains("#40cc40"), E.add("Affordable cost green: ", locale)) - check(text.contains("4.0000E+10"), E.add("Lifespan substituted: ", locale)) + check(text.contains("40 000 000 000"), E.add("Lifespan substituted: ", locale)) text = description.render(world, global, "He") check((text.contains("He: 20.00% / H: 80.00%") and (not text.contains("%value"))), E.add("Helium metadata and mixture: ", locale)) text = description.render(world, global, "Shovelin", "Force") diff --git a/tests/test_dynamic_math.gd b/tests/test_dynamic_math.gd new file mode 100644 index 0000000..832a650 --- /dev/null +++ b/tests/test_dynamic_math.gd @@ -0,0 +1,72 @@ +extends SceneTree +const E = preload("res://world/owniverse/math/exact.gd") +const B = preload("res://world/owniverse/math/big_integer.gd") +var checks: int = 0 +var failures: int = 0 + +func verify(condition: bool, label: String): + checks += 1 + if not condition: + failures += 1 + push_error(label) + +func _initialize(): + call_deferred("run") + +func run(): + var rng = RandomNumberGenerator.new() + rng.seed = 619 + for trial in 300: + var n: int = rng.randi_range(0, 100) + var m: int = rng.randi_range(1, 100) + var a: int = rng.randi_range(0, 1000) + var b: int = rng.randi_range(0, 1000) + var expected: int = 0 + for i in n: expected += (a * i + b) / m + verify(E.eq(E.floor_sum(n, a, b, m), expected), "floor sum matches explicit windows") + var huge = E.of("1e40") + verify(E.lt(E.of("1e1000"), INF), "finite huge number is below positive infinity") + verify(E.gt(E.of("-1e1000"), -INF), "finite huge negative number is above negative infinity") + verify(E.gt(INF, E.of("1e1000")), "positive infinity is above finite huge number") + verify(not E.eq(E.of("1e1000"), INF), "huge number is not infinity") + verify(E.eq(E.floor_sum(huge, 2, 1, 2), E.divide(E.multiply(huge, E.subtract(huge, 1)), 2)), "floor sum supports huge window counts") + var rows = JSON.parse_string(FileAccess.get_file_as_string("res://tests/fixtures/big_integer_oracle.json")) + for row in rows: + var a: Array = B.parse(row[0]) + var b: Array = B.parse(row[1]) + var qr: Array = B.divmod(a, b) + verify(B.decimal(B.add(a, b)) == row[2], "independent big sum") + verify(B.decimal(B.multiply(a, b)) == row[3], "independent big product") + verify(B.decimal(qr[0]) == row[4], "independent big quotient") + verify(B.decimal(qr[1]) == row[5], "independent big remainder") + verify(E.fixed(E.multiply(E.of(row[0]), E.of(row[1]))) == row[3], "dynamic product") + verify(E.eq(E.mul_div(E.of(row[0]), E.of(row[1]), E.of(row[1])), E.of(row[0])), "fused conservation") + for text in ["9223372036854775807", "-9223372036854775808", "9223372036854775808", "-9223372036854775809", "1e300", "1e1000"]: + var n = E.of(text) + verify(E.eq(E.subtract(E.add(n, 1), n), 1), "unit preserved at " + text) + verify(E.eq(E.decode(JSON.parse_string(JSON.stringify(E.encode(n)))), n), "round trip " + text) + for text in ["1.25", "-1.25", "123.5"]: + verify(E.approx(E.of(text)) == float(text), "approx fraction " + text) + verify(not E.valid_encoded({"$exact": [[], "0000000000000000", 1]}), "reject empty blocks") + verify(not E.valid_encoded({"$exact": [[1, 0], "0000000000000000", 1]}), "reject noncanonical blocks") + verify(E.gt(E.power(E.of("1e400"), -1), 0) == false, "float fraction underflows beyond its range") + verify(absf(E.approx(E.logarithm(E.of("1e1000"))) - 1000 * log(10.0)) < 1e-8, "logarithm beyond float range") + verify(E.eq(E.square_root(E.of("1e1000")), E.of("1e500")), "square root beyond float range") + var world = load("res://world/owniverse/owniverse.gd").new() + world.catalog.load_definitions(root.get_node("Global").OwniverseEntities) + for id in world.catalog.entities: + world.state.amount[id] = 0 + world.state.stats.total_amount[id] = 0 + var group: String = world.catalog.entities[id].group_as + if group != "": + world.state.amount[group] = 0 + world.state.stats.total_amount[group] = 0 + world.state.amount.H = E.of("1e1000") + world.state.amount.S = E.of("1e1000") + var environment: Dictionary = world.environment.stellar_environment(world.state) + verify(E.finite(environment.density) and E.gt(environment.density, 0), "huge density remains finite") + verify(E.near(environment.blast, 1), "huge geometric ratio stays valid") + for entity in world.catalog.entities.values(): entity.free() + world.free() + print("Dynamic math: %d checks, %d failures" % [checks, failures]) + quit(1 if failures else 0) diff --git a/tests/test_dynamic_math.gd.uid b/tests/test_dynamic_math.gd.uid new file mode 100644 index 0000000..186ccfe --- /dev/null +++ b/tests/test_dynamic_math.gd.uid @@ -0,0 +1 @@ +uid://8vkudj0tlnng diff --git a/tests/test_exact_math.gd b/tests/test_exact_math.gd index 50c907b..4f793ae 100644 --- a/tests/test_exact_math.gd +++ b/tests/test_exact_math.gd @@ -94,7 +94,7 @@ func run(): check(str(world.state.auto_star_deficits).length() < 500, "true", "fraction storage stays bounded") print("100 changing-composition cycles: %d ms" % (Time.get_ticks_msec() - started)) var saves = root.get_node("SaveManager") - check(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), "", "long-running state saves") + check(saves.validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), "", "long-running state saves") for entity in world.catalog.entities.values(): entity.free() world.free() print("Exact math: %d checks, %d failures" % [checks, failures]) diff --git a/tests/test_frame_evolution.gd b/tests/test_frame_evolution.gd new file mode 100644 index 0000000..5b8abe5 --- /dev/null +++ b/tests/test_frame_evolution.gd @@ -0,0 +1,100 @@ +extends SceneTree +const E = preload("res://world/owniverse/math/exact.gd") +const Clock = preload("res://world/owniverse/simulation_time.gd") +const Fixture = preload("res://tests/fixtures/civilization_benchmark.gd") +var checks: int = 0 +var failures: int = 0 + +func _initialize(): call_deferred("run") +func check(condition: bool, message: String): + checks += 1 + if not condition: + failures += 1 + push_error(message) +func fixture(): + var world = load("res://world/owniverse/owniverse.gd").new() + world.catalog.load_definitions(root.get_node("Global").OwniverseEntities) + Fixture.seed(world, root.get_node("Global")) + return world +func dispose(world): + for entity in world.catalog.entities.values(): entity.free() + world.free() + +func run(): + Engine.max_fps = 0 + var direct = fixture() + var sliced = fixture() + for delta in [1.0 / 60.0, 0.133333333333]: + direct.evolute(delta) + var clock: Dictionary = Clock.advance(sliced.state.time, delta, sliced.speed) + var budget = load("res://world/owniverse/frame_budget.gd").new(self, 1) + await sliced.evolution.evolute_to_datetime(clock.datetime, clock, budget) + check(E.eq(direct.state, sliced.state), "Sliced transaction exactly matches uninterrupted evolution") + dispose(direct) + dispose(sliced) + direct = fixture() + sliced = fixture() + var initial_h: Variant = sliced.state.amount.H + sliced.evolute_frame(1.0 / 60.0, self) + check(sliced.frame_busy, "Heavy transaction yields before publishing") + check(E.eq(sliced.state.time.year, 0), "Published clock stays at completed transaction") + sliced.request_production("H", 1, true) + check(E.eq(sliced.state.amount.H, initial_h), "Player action waits for transaction commit") + sliced.evolute_frame(0.01, self) + var requested: Dictionary = sliced.frame_clock.duplicate() + sliced.speed = 3 + check(sliced.speed == 3 and sliced.state.speed == 6, "Speed change is visible and cannot mutate an unfinished transaction") + while sliced.frame_busy: await process_frame + direct.evolute(1.0 / 60.0) + direct.production.produce_hs("H", 1) + direct.speed = 3 + check(E.eq(direct.state, sliced.state), "Queued action and speed change survive publication") + sliced.evolute_frame(0.001, self) + var second_clock: Dictionary = Clock.advance(requested, 0.001, 3) + var active: Dictionary = sliced.frame_active_clock.duplicate() + while sliced.frame_busy: await process_frame + direct.evolution.evolute_to_datetime(active.datetime, active) + check(E.eq(direct.state, sliced.state), "Bounded frame transaction matches its exact target clock") + check(E.eq(sliced.frame_clock, second_clock), "All elapsed time during a busy frame remains in the requested clock") + check(sliced.frame_commits == 2, "Only complete simulation states are committed") + dispose(direct) + dispose(sliced) + var original = fixture() + original.evolute_frame(1.0 / 60.0, self) + original.request_production("H", 123, true) + original.evolute_frame(0.01, self) + original.speed = 3 + var checkpoint: Dictionary = E.decode(E.encode(original.frame_checkpoint())) + var published: Dictionary = E.decode(E.encode(original.state)) + var expected_clock: Dictionary = original.frame_active_clock.duplicate() + dispose(original) + for frame in 3: await process_frame + var resumed = fixture() + var expected = fixture() + resumed.state = published.duplicate(true) + expected.state = published.duplicate(true) + resumed.restore_frame_checkpoint(checkpoint) + resumed.evolute_frame(0.0, self) + while resumed.frame_busy: await process_frame + expected.evolution.evolute_to_datetime(expected_clock.datetime, expected_clock) + expected.production.produce_hs("H", 123) + expected.speed = 3 + check(E.eq(expected.state, resumed.state), "Checkpoint recomputes interrupted transaction and preserves queued production") + check(E.eq(resumed.frame_clock, checkpoint.requested_clock), "Checkpoint preserves all requested elapsed time") + dispose(resumed) + dispose(expected) + var cancelled = fixture() + cancelled.evolute_frame(0.133333333333, self) + check(cancelled.frame_busy, "Cancellation fixture has suspended work") + var budget_ref: RefCounted = cancelled.frame_budget + dispose(cancelled) + for frame in 3: await process_frame + check(budget_ref.cancelled, "Resetting the world cancels suspended work without publishing") + var invalid = fixture() + var before: Dictionary = invalid.state.duplicate(true) + invalid.evolute_frame(1e308, self) + invalid.evolute(1e308) + check(not invalid.frame_busy and invalid.frame_clock.is_empty() and E.eq(before, invalid.state), "Overflowing elapsed float cannot enter either clock API") + dispose(invalid) + print("Frame evolution: %d checks, %d failures" % [checks, failures]) + quit(1 if failures else 0) diff --git a/tests/test_frame_evolution.gd.uid b/tests/test_frame_evolution.gd.uid new file mode 100644 index 0000000..a98c6ec --- /dev/null +++ b/tests/test_frame_evolution.gd.uid @@ -0,0 +1 @@ +uid://te15r63sqhxs diff --git a/tests/test_life.gd b/tests/test_life.gd index 7ca6cb1..2618140 100644 --- a/tests/test_life.gd +++ b/tests/test_life.gd @@ -54,7 +54,7 @@ func run() -> void: check(E.gt(world.state.batches.HP.size(), 0), "Survivors get next attempt") var physical: Dictionary = world.ledger.physical_amounts(world.state) check(E.eq(E.add(E.add(physical.HP, physical.EON1), physical.RP), 40000), "Life conserves planets") - check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Life save validates") + check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Life save validates") var restored = fixture() restored.state = E.decode(bytes_to_var(var_to_bytes(E.encode(world.state)))) world.evolution.evolve_batches(world.state, 11000000) @@ -118,7 +118,7 @@ func run() -> void: world.evolution.evolve_batches(world.state, 2050) check(E.eq(world.state.binds.RD["C0.2"], 700), "C0.1 reaches ethical civilization without losing host") check(E.eq(world.state.binds.RD["C0.0"], 1000), "C0.1 degradation follows Unity") - check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Extended life save validates") + check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Extended life save validates") dispose(world) print(("Life: %d checks, %d failures" % [checks, failures])) quit((0 if E.eq(failures, 0) else 1)) diff --git a/tests/test_quantity_catalog.gd b/tests/test_quantity_catalog.gd index 4f36d57..8b1f340 100644 --- a/tests/test_quantity_catalog.gd +++ b/tests/test_quantity_catalog.gd @@ -2,6 +2,7 @@ extends SceneTree const E = preload("res://world/owniverse/math/exact.gd") const Math = preload("res://world/owniverse/quantity_math.gd") +const Legacy = preload("res://tests/fixtures/legacy_quantity_math.gd") var checks: int = 0 var failures: int = 0 @@ -15,6 +16,24 @@ func check(condition: bool, message: String) -> void: push_error(message) func run() -> void: + var rng = RandomNumberGenerator.new() + rng.seed = 65432 + var old_remainders: Dictionary = {} + var new_remainders: Dictionary = {} + for sample in 300: + var requests: Dictionary = {} + var weights: Dictionary = {} + for id in ["w", "m", "b", "c", "d", "l"]: + requests[id] = E.of(str(rng.randi_range(-10, 100)) + "." + str(rng.randi_range(0, 9))) + weights[id] = rng.randi_range(0, 100) + if sample % 3 == 0: + for id in requests: requests[id] = E.multiply(requests[id], E.of("1e40")) + var limit: Variant = E.multiply(rng.randi_range(0, 600), E.of("1e40")) if sample % 3 == 0 else rng.randi_range(0, 600) + check(E.eq(Math.allocate_whole(requests, limit), Legacy.allocate_whole(requests, limit)), "Allocation matches legacy with limits, ties and big integers") + var count: Variant = limit + check(E.eq(Math.split(new_remainders, "population", count, weights), Legacy.split(old_remainders, "population", count, weights)), "Split matches legacy rounding") + check(E.eq(new_remainders, old_remainders), "Signed remainder debt matches legacy") + check_ledger_cache() var Catalog = load("res://world/owniverse/entity_catalog.gd") check(E.eq(Math.allocate_whole({}, 10), {}), "Empty allocation") check(E.eq(Math.allocate_whole({"b": 1, "a": 1}, 1), {"a": 1, "b": 0}), "Stable lexical tie") @@ -62,3 +81,32 @@ func run() -> void: for entity in catalog.entities.values(): entity.free() print(("Quantity and catalog: %d checks, %d failures" % [checks, failures])) quit((1 if failures else 0)) + +func check_ledger_cache() -> void: + var world = load("res://world/owniverse/owniverse.gd").new() + world.catalog.load_definitions(root.get_node("Global").OwniverseEntities) + world.state.amount.RD = E.of("1e40") + world.state.binds.GEM = {"RD": 7} + check(E.eq(world.ledger.physical_amounts(world.state).RD, E.add(E.of("1e40"), 7)), "Initial cached physical amount") + var returned: Dictionary = world.ledger.physical_amounts(world.state) + returned.RD = 0 + check(E.gt(world.ledger.physical_amounts(world.state).RD, 0), "Caller cannot mutate cached physical totals") + world.state.binds.GEM.RD = 11 + check(E.eq(world.ledger.physical_amounts(world.state).RD, E.add(E.of("1e40"), 11)), "Nested binding change invalidates physical cache") + world.state.amount.RD = 2 + check(E.eq(world.ledger.physical_amounts(world.state).RD, 13), "Direct count change invalidates physical cache") + var other: Dictionary = world.state.duplicate(true) + other.binds.clear() + check(E.eq(world.ledger.physical_amounts(other).RD, 2), "Alternate state has independent physical totals") + check(E.eq(world.ledger.physical_amounts(world.state).RD, 13), "Returning to original state refreshes cache") + var revision: int = world.catalog.index_revision + world.catalog.rebuild_group_index() + check(world.catalog.index_revision > revision, "Catalog rebuild invalidates cached membership") + check(E.eq(world.ledger.physical_amounts(world.state).RD, 13), "Rebuild retains correct physical totals") + var rules: Dictionary = root.get_node("Global").CivilizationRules.duplicate(true) + var original_stages: int = world.catalog.civilization_layout(rules).stages.size() + rules["C2.0"].home = "" + world.catalog.invalidate_civilization_layout() + check(world.catalog.civilization_layout(rules).stages.size() == original_stages - 1, "Explicit rules change rebuilds civilization layout") + for entity in world.catalog.entities.values(): entity.free() + world.free() diff --git a/tests/test_short_lived_events.gd b/tests/test_short_lived_events.gd index bbbc343..f6fa217 100644 --- a/tests/test_short_lived_events.gd +++ b/tests/test_short_lived_events.gd @@ -38,8 +38,11 @@ func equivalent(a: Variant, b: Variant) -> bool: for i in a.size(): if (not equivalent(a[i], b[i])): return false return true - if ((((a is float) or (a is int))) and (((b is float) or (b is int)))): - return E.lt(E.absolute(E.subtract(E.of(a), E.of(b))), E.of("1e-6")) + if E.numeric(a) and E.numeric(b): + # Counts must match exactly. Fractional float remainders can differ + # when the analytic integral replaces thousands of subtractions. + if not E.eq(E.floor_value(a), E.floor_value(b)): return false + return E.le(E.absolute(E.subtract(a, b)), E.of("1e-8")) return E.eq(a, b) func run() -> void: @@ -75,6 +78,19 @@ func run() -> void: for batch in fast.state.batches.SN: total = E.add(total, batch.amount) check(E.eq(total, 10000), "Direct completions plus survivors conserve event count") dispose(fast) + # Dense completed events must not iterate a million elapsed windows. + # An aligned, fully completed cohort produces exactly count * lifespan. + fast = fixture(false) + pending = {} + var lifespan: Variant = fast.catalog.entities.SN.lifespan + var window: Variant = E.divide(lifespan, root.get_node("Global").batch_count) if E.gt(lifespan, 10) else lifespan + var creation_end: Variant = E.multiply(window, 1000000) + var dense_count: Variant = E.of("1e20") + var integral: Variant = fast.batches.append_batch(fast.state, "SN", dense_count, 0, creation_end, pending, E.add(creation_end, lifespan)) + check(E.eq(pending.SN[0].amount, dense_count), "Million-window aggregation conserves every event") + check(E.eq(integral, E.multiply(dense_count, lifespan)), "Million-window aggregation preserves lifetime integral") + check(fast.state.batches.SN.is_empty(), "Completed million-window cohort leaves no transient batches") + dispose(fast) # Sparse explosions: thousands of time windows but very few actual events. # Exact interval edges and partial final windows exercise the jump boundary. for count in [1, 3, 17]: diff --git a/tests/test_sparse_batches.gd b/tests/test_sparse_batches.gd new file mode 100644 index 0000000..e55a495 --- /dev/null +++ b/tests/test_sparse_batches.gd @@ -0,0 +1,52 @@ +extends SceneTree +const E = preload("res://world/owniverse/math/exact.gd") +var checks: int = 0 +var failures: int = 0 +func _initialize(): call_deferred("run") +func check(value: bool, message: String): + checks += 1 + if not value: + failures += 1 + push_error(message) +func run(): + var world = load("res://world/owniverse/owniverse.gd").new() + world.catalog.load_definitions(root.get_node("Global").OwniverseEntities) + world.catalog.entities.N.lifespan = 24 + var width: Variant = E.divide(24, root.get_node("Global").batch_count) + for count in [1, 2, 7, 11, 100, E.of("1e40")]: + for interval in [[E.of("0.25"), E.of("101.75")], [0, 120], [3, 3]]: + world.state.batches = {} + world.state.batch_origins = {"N": E.of("0.125")} + var expected: Array = [] + var origin: Variant = world.state.batch_origins.N + var index: Variant = E.floor_value(E.divide(E.subtract(interval[0], origin), width)) + var assigned: Variant = 0 + var cursor: Variant = interval[0] + while true: + var start: Variant = E.add(origin, E.multiply(index, width)) + var end: Variant = E.add(origin, E.multiply(E.add(index, 1), width)) + if E.le(end, cursor): + index = E.add(index, 1) + continue + var until: Variant = E.minimum(interval[1], end) + var amount: Variant = E.subtract(count, assigned) + if E.gt(interval[1], interval[0]) and E.lt(until, interval[1]): + amount = E.subtract(E.floor_value(E.mul_div(count, E.subtract(until, interval[0]), E.subtract(interval[1], interval[0]))), assigned) + if E.gt(amount, 0): + expected.append({"created_from": start, "created_to": end, "start_year": E.add(start, 24), "end_year": E.add(end, 24), "amount": amount}) + assigned = E.add(assigned, amount) + if E.ge(until, interval[1]): break + cursor = end + index = E.add(index, 1) + world.batches.append_batch(world.state, "N", count, interval[0], interval[1]) + var actual: Array = [] + for batch in world.state.batches.N: + if E.gt(batch.amount, 0): actual.append(batch) + check(E.eq(actual, expected), "Sparse jump preserves every nonempty quota and boundary") + var total: Variant = 0 + for batch in actual: total = E.add(total, batch.amount) + check(E.eq(total, count), "Sparse jump preserves complete whole population") + for entity in world.catalog.entities.values(): entity.free() + world.free() + print("Sparse batches: %d checks, %d failures" % [checks, failures]) + quit(1 if failures else 0) diff --git a/tests/test_sparse_batches.gd.uid b/tests/test_sparse_batches.gd.uid new file mode 100644 index 0000000..0f01edb --- /dev/null +++ b/tests/test_sparse_batches.gd.uid @@ -0,0 +1 @@ +uid://gtvie7p6j62x diff --git a/tests/test_stellar_rules.gd b/tests/test_stellar_rules.gd index b4b62fd..973227b 100644 --- a/tests/test_stellar_rules.gd +++ b/tests/test_stellar_rules.gd @@ -96,7 +96,7 @@ func run() -> void: check((E.eq(world.state.binds.RD.GG, 16) and E.eq(world.state.binds.RD.AB, 120)), "Planet multiplicity applied") check((E.eq(world.state.amount.HP, 0) and E.eq(world.state.stats.total_amount.HP, 1)), "Created planets are bound, counted once") var saves: Node = root.get_node("SaveManager") - check(E.eq(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Planet carry save validates") + check(E.eq(saves.validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Planet carry save validates") restored = fixture() restored.state = E.decode(bytes_to_var(var_to_bytes(E.encode(world.state)))) world.stellar.create_planets(world.state, "RD", 37, 0, 0, E.of("0.7")) @@ -118,7 +118,7 @@ func run() -> void: check((E.eq(world.state.amount.RP, 0) and E.eq(world.state.amount["C1.3"], 0)), "Inherited planets never become free") world.evolution.evolve_batches(world.state, E.add(lifespan, width)) check((E.eq(world.state.binds.RD["C1.3"], 0) and E.eq(world.state.binds.TWD["C1.3"], 4)), "No planets left at extinct parent type") - check(E.eq(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Inherited state validates") + check(E.eq(saves.validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Inherited state validates") dispose(world) world = fixture() @@ -158,7 +158,7 @@ func run() -> void: check((E.eq(world.state.amount.SN, 0) and E.eq(world.state.amount.LNS, 1)), "Supernova produces a remnant") check(((E.eq(world.state.amount.H, 8) and E.eq(world.state.amount.He, 50)) and E.eq(world.state.amount.Met, 11)), "Supernova returns table resources") check((not world.state.amount.has("blast")), "Supernova dispatches blast output") - check(E.eq(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Blast state validates") + check(E.eq(saves.validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Blast state validates") dispose(world) world = fixture() diff --git a/tests/test_time.gd b/tests/test_time.gd index 545c1bd..3376e2e 100644 --- a/tests/test_time.gd +++ b/tests/test_time.gd @@ -51,10 +51,10 @@ func run() -> void: for invalid in [0, E.neg(1), NAN, INF, 1e308]: world.evolute(invalid) check(E.eq(world.state, before), "Invalid/overflow interval rejected") - check(E.eq(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Fractional save is valid") + check(E.eq(saves.validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Fractional save is valid") var invalid_save: Dictionary = world.state.duplicate(true) invalid_save.time.year = E.of("0.25") - check(E.ne(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": invalid_save}), ""), "Reject inconsistent fractional clock") + check(E.ne(saves.validate_data({"format_version": 5, "app_version": "", "ui": {"current_page": 0}, "state": invalid_save}), ""), "Reject inconsistent fractional clock") dispose(world) for fps in [30, 60, 144]: diff --git a/tests/test_world_indicators.gd b/tests/test_world_indicators.gd index 3ea4be8..217f8cc 100644 --- a/tests/test_world_indicators.gd +++ b/tests/test_world_indicators.gd @@ -133,7 +133,7 @@ func run() -> void: Parameters.advance(source, world.state, rules, E.of("1.0e12")) check((E.ge(world.state.trends.Integration, 0) and E.lt(world.state.trends.Integration, 1)), "Very large intervals finish with a valid trend fraction") check(E.ge(world.state.world_parameters.Agg, 1), "Repeated integration events cannot reduce aggression below the scale") - var payload: Dictionary = {"format_version": 4, "app_version": "test", "ui": {"current_page": 1}, "state": world.state} + var payload: Dictionary = {"format_version": 5, "app_version": "test", "ui": {"current_page": 1}, "state": world.state} var manager: Node = root.get_node("SaveManager") check(E.eq(manager.validate_data(payload), ""), "New parameters and trends pass save validation") var old: Dictionary = payload.duplicate(true) diff --git a/ui/owniverse_item/owniverse_item.gd b/ui/owniverse_item/owniverse_item.gd index c39a0e3..a0a44c2 100644 --- a/ui/owniverse_item/owniverse_item.gd +++ b/ui/owniverse_item/owniverse_item.gd @@ -1,5 +1,6 @@ extends Control class_name OwniverseItem +const E = preload("res://world/owniverse/math/exact.gd") signal item_activated(item) @@ -20,7 +21,7 @@ var item_type = "" func set_label(value) -> void: - var text: String = Global.format_number(value) + var text: String = E.scientific(value, 5) if E.gt(E.absolute(value), 1000000000) else (E.grouped(value, 0, false) if E.ne(value, 0) else "") if description.text != text: description.text = text #description.text = str(value) diff --git a/world/owniverse/automatic_production.gd b/world/owniverse/automatic_production.gd index afcbefe..a19f488 100644 --- a/world/owniverse/automatic_production.gd +++ b/world/owniverse/automatic_production.gd @@ -217,11 +217,7 @@ func produce_newborn_lifetime(target: Dictionary, id: String, count: Variant, bo object_years = E.maximum(0, object_years) for resource in products: var coefficient: Variant = E.multiply(products[resource], WorldParameters.production(target, world.catalog.entities[id])) - # A giant cohort can accumulate more than E27 object-years. Clamp the - # multiplicand before multiplying so the exact-number backend never - # constructs an out-of-range intermediate value. - var safe_years: Variant = (E.minimum(object_years, E.divide(E.max_value(), coefficient)) if E.gt(coefficient, 0) else 0) - var output: Variant = E.multiply(safe_years, coefficient) + var output: Variant = E.multiply(object_years, coefficient) if E.contains(["H", "S"], resource): output = E.minimum(output, target.energy) var actual: Variant = world.ledger.credit(target, resource, output) diff --git a/world/owniverse/civilization_evolution.gd b/world/owniverse/civilization_evolution.gd index e4d4d1b..bf9eb58 100644 --- a/world/owniverse/civilization_evolution.gd +++ b/world/owniverse/civilization_evolution.gd @@ -26,7 +26,7 @@ static func rate(target: Dictionary, key: String, count: Variant, probability: V # Fixed-size largest-remainder apportionment with saved signed rounding errors. # Runtime depends on the number of branches, never the number of civilizations. static func split(target: Dictionary, key: String, count: Variant, weights: Dictionary) -> Dictionary: - if (E.le(count, 0) or E.le(QuantityMath.sum(weights), 0)): return {} + if E.le(count, 0): return {} if (not target.has("civilization_remainders")): target.civilization_remainders = {} return QuantityMath.split(target.civilization_remainders, key, count, weights) @@ -34,11 +34,12 @@ static func drift(target: Dictionary, key: String, pop: Dictionary, rows: Dictio var weights: Dictionary = {} for ethic in pop: var influence: Variant = (E.of(rows[ethic].diplomacy_rate) if diplomacy else 1) + var contribution: Variant = E.multiply(pop[ethic], influence) for other in ETHICS: var weight: Variant = (9 if colony else 1) if E.eq(other, ethic): weight = (960 if colony else 196) elif E.eq(other, OPPOSITE[ethic]): weight = (4 if colony else 0) - weights[other] = E.add(weights.get(other, 0), E.multiply(E.multiply(pop[ethic], influence), weight)) + weights[other] = E.add(weights.get(other, 0), E.multiply(contribution, weight)) if E.le(total(weights), 0): return pop.duplicate() return split(target, key, total(pop), weights) @@ -48,6 +49,7 @@ static func emit(plan: Dictionary, destination: String, pop: Dictionary) -> void static func fall(target: Dictionary, plan: Dictionary, rules: Dictionary, pop: Dictionary) -> void: for ethic in pop: + if E.le(pop[ethic], 0): continue var weights: Dictionary = {} for term in str(rules[plan.id].ethics[ethic].fall).split("^", false): var pair: PackedStringArray = term.split(":") @@ -76,9 +78,11 @@ static func consume_untriggered(world, target: Dictionary, plan: Dictionary, pop plan.to = E.maximum(plan.to, year) return removed -static func prepare(world, target: Dictionary, expired: Dictionary, year: Variant, budget: Dictionary, rules: Dictionary, physical: Dictionary = {}) -> Dictionary: +static func prepare(world, target: Dictionary, expired: Dictionary, year: Variant, budget: Dictionary, rules: Dictionary, physical: Dictionary = {}, budget_timer: RefCounted = null) -> Dictionary: + var profile_started: int = world.profile_start() State.reconcile(world, target, rules, physical) - var remaining: Dictionary = target.ethics.duplicate(true) + var remaining: Dictionary = target.ethics.duplicate() + var copied: Dictionary = {} var plans: Dictionary = {} var colonies: Array = [] var collateral: Dictionary = {} @@ -88,6 +92,7 @@ static func prepare(world, target: Dictionary, expired: Dictionary, year: Varian var ids: Array = expired.keys() ids.sort() for id in ids: + if budget_timer != null and not await budget_timer.pause(): return {} if ((not rules.has(id)) or expired[id].is_empty()): continue var plan: Dictionary = new_plan(id, year) plans[id] = plan @@ -95,6 +100,8 @@ static func prepare(world, target: Dictionary, expired: Dictionary, year: Varian plan.amount = E.add(plan.amount, part.amount) plan.from = E.minimum(plan.from, part.from) plan.to = E.maximum(plan.to, part.to) + remaining[id] = remaining[id].duplicate() + copied[id] = true var triggered: Dictionary = take(world, remaining[id], plan.amount) var successes: Dictionary = {} var failures: Dictionary = {} @@ -113,9 +120,12 @@ static func prepare(world, target: Dictionary, expired: Dictionary, year: Varian successes[ethic] = bounded.pro failures[ethic] = bounded.deg triggered[ethic] = E.subtract(triggered[ethic], E.add(bounded.pro, bounded.deg)) + var profile_transitions: int = world.profile_start() add(triggered, progress(world, target, rules, budget, plan, successes)) fall(target, plan, rules, failures) + world.profile_end("civilization_transitions", profile_transitions) if rules[id].fights: + var profile_wars: int = world.profile_start() for ethic in warriors: warriors[ethic] = E.minimum(warriors[ethic], triggered[ethic]) var wars: Variant = E.minimum(total(warriors), E.floor_value(E.divide((E.add(total(triggered), total(remaining[id]))), 2))) warriors = QuantityMath.allocate_whole(warriors, wars) @@ -136,11 +146,15 @@ static func prepare(world, target: Dictionary, expired: Dictionary, year: Varian var damage: Variant = rate(target, E.add(id, ":collateral"), E.divide((E.add(E.multiply(outcomes.get("pro50", 0), 10), E.multiply(outcomes.get("pro75", 0), 30))), order), 1) collateral[rules[id].previous] = E.add(collateral.get(rules[id].previous, 0), damage) target.civilization_stats.wars = E.add(target.civilization_stats.get("wars", 0), wars) + world.profile_end("wars", profile_wars) emit(plan, id, triggered) if E.gt(total(settlers), 0): colonies.append({"stage": rules[id].colony, "source": id, "population": settlers}) # Collateral is applied after all stages planned their own attempts. for id in collateral: if (not rules.has(id)): continue + if not copied.has(id): + remaining[id] = remaining[id].duplicate() + copied[id] = true if (not plans.has(id)): plans[id] = new_plan(id, year) var plan: Dictionary = plans[id] var retry: Dictionary = plan.outputs.get(id, {}) @@ -153,22 +167,27 @@ static func prepare(world, target: Dictionary, expired: Dictionary, year: Varian var incoming: Dictionary = {} var planetary: Dictionary = {} for id in plans: + if budget_timer != null and not await budget_timer.pause(): return {} var plan: Dictionary = plans[id] var products: Dictionary = {} for destination in plan.outputs: var pop: Dictionary = plan.outputs[destination] if rules.has(destination): if E.ne(destination, "Ct"): + var profile_drift: int = world.profile_start() pop = drift(target, E.add(E.add(E.add(id, ":"), destination), ":drift"), pop, rules[id].ethics, (E.eq(destination, id) and rules[id].diplomacy)) + world.profile_end("ethics_drift", profile_drift) if (not incoming.has(destination)): incoming[destination] = {} add(incoming[destination], pop) products[destination] = total(pop) if (State.is_space_civilization(id, rules) and E.eq(world.catalog.entities[destination].group_as, "Planet")): planetary[destination] = E.add(planetary.get(destination, 0), total(pop)) expired[id] = [{"amount": plan.amount, "from": plan.from, "to": E.maximum(plan.from, plan.to), "products": products}] + world.profile_end("civilization_prepare", profile_started) return {"remaining": remaining, "incoming": incoming, "planetary": planetary, "colonies": colonies} -static func finish(world, target: Dictionary, transaction: Dictionary, year: Variant, rules: Dictionary) -> void: +static func finish(world, target: Dictionary, transaction: Dictionary, year: Variant, rules: Dictionary, budget_timer: RefCounted = null) -> void: + var profile_started: int = world.profile_start() target.ethics = transaction.remaining for id in transaction.incoming: if (not target.ethics.has(id)): target.ethics[id] = {} @@ -184,22 +203,30 @@ static func finish(world, target: Dictionary, transaction: Dictionary, year: Var if (not target.binds.has(owner)): target.binds[owner] = {} target.binds[owner][id] = E.add(target.binds[owner].get(id, 0), shares[owner]) target.amount[id] = E.subtract(target.amount[id], shares[owner]) - colonize(world, target, transaction.colonies, year, rules) - State.reconcile(world, target, rules) + if budget_timer != null: + await colonize(world, target, transaction.colonies, year, rules, physical, budget_timer) + if budget_timer.cancelled: return + else: + colonize(world, target, transaction.colonies, year, rules, physical) + State.reconcile(world, target, rules, physical if transaction.colonies.is_empty() else {}) var worship: Variant = 0 for id in rules: if (not rules[id].worships): continue for ethic in target.ethics[id]: worship = E.add(worship, E.multiply(target.ethics[id][ethic], E.of(rules[id].ethics[ethic].worship))) target.civilization_stats.worship = worship + world.profile_end("civilization_finish", profile_started) -static func colonize(world, target: Dictionary, colonies: Array, year: Variant, rules: Dictionary) -> void: - var physical: Dictionary = world.ledger.physical_amounts(target) +static func colonize(world, target: Dictionary, colonies: Array, year: Variant, rules: Dictionary, physical: Dictionary = {}, budget_timer: RefCounted = null) -> void: + if colonies.is_empty(): return + var profile_colonies: int = world.profile_start() + if physical.is_empty(): physical = world.ledger.physical_amounts(target) var stock: Dictionary = {} for id in ["GG", "AB", "RP", "HP"]: stock[id] = physical.get(id, 0) var requests: Dictionary = {} for i in colonies.size(): requests[str(i)] = total(colonies[i].population) var granted: Dictionary = QuantityMath.allocate_whole(requests, total(stock)) for i in colonies.size(): + if budget_timer != null and not await budget_timer.pause(): return var colony: Dictionary = colonies[i] var population: Dictionary = QuantityMath.allocate_whole(colony.population, granted[str(i)]) population = drift(target, E.add(colony.source, ":colonies"), population, rules[colony.source].ethics, false, true) @@ -225,3 +252,4 @@ static func colonize(world, target: Dictionary, colonies: Array, year: Variant, if (not target.ethics.has(colony.stage)): target.ethics[colony.stage] = {} add(target.ethics[colony.stage], population) target.civilization_stats.colonies = E.add(target.civilization_stats.get("colonies", 0), count) + world.profile_end("colonization", profile_colonies) diff --git a/world/owniverse/civilization_state.gd b/world/owniverse/civilization_state.gd index c08acb1..377da42 100644 --- a/world/owniverse/civilization_state.gd +++ b/world/owniverse/civilization_state.gd @@ -44,12 +44,11 @@ static func detach_space_civilizations(target: Dictionary, rules: Dictionary) -> static func stellar_budget(world, target: Dictionary, rules: Dictionary, physical: Dictionary = {}) -> Dictionary: if physical.is_empty(): physical = world.ledger.physical_amounts(target) + var layout: Dictionary = world.catalog.civilization_layout(rules) var capacity: Dictionary = {} - for id in physical: - var entity = world.catalog.entities[id] - for home in ["DwStar", "GiStar", "WD", "NS", "MGT", "BH"]: - if ((E.eq(entity.event_group, home) or E.eq(entity.count_as, home)) or E.eq(id, home)): - capacity[home] = E.add(capacity.get(home, 0), physical[id]) + for id in layout.star_homes: + for home in layout.star_homes[id]: + capacity[home] = E.add(capacity.get(home, 0), physical.get(id, 0)) capacity["SMBH"] = E.maximum(0, target.amount.get("SMBH", 0)) for held : Dictionary in target.binds.values(): capacity["SMBH"] = E.add(capacity["SMBH"], E.maximum(0, held.get("SMBH", 0))) @@ -106,22 +105,21 @@ static func admit_transition(budget: Dictionary, rules: Dictionary, source: Stri # Resolve shortages from the most advanced stages downwards. This gives existing # advanced populations priority and lets a demotion cascade in the same cycle. static func enforce_capacity(world, target: Dictionary, rules: Dictionary, year: Variant) -> void: + var profile_started: int = world.profile_start() detach_space_civilizations(target, rules) var physical: Dictionary = world.ledger.physical_amounts(target) reconcile(world, target, rules, physical) var budget: Dictionary = stellar_budget(world, target, rules, physical) var remaining: Dictionary = budget.capacity.duplicate() var remaining_homes: Dictionary = budget.habitats.capacity.duplicate() - var stages: Array = [] - for id in rules: - if is_space_civilization(id, rules): - stages.append(id) - stages.sort() + var stages: Array = world.catalog.civilization_layout(rules).stages + var changed: bool = false for index in range(E.subtract(stages.size(), 1), E.neg(1), E.neg(1)): var id: String = stages[index] + var count: Variant = target.amount.get(id, 0) + if E.le(count, 0): continue var home: String = rules[id].home var cost: Variant = E.maximum(1, rules[id].stars) - var count: Variant = target.amount.get(id, 0) var supported: Variant = E.minimum(count, E.floor_value(E.divide(remaining.get(home, 0), cost))) var requirement: Dictionary = budget.habitats.requirements.get(id, {}) if (not requirement.is_empty()): @@ -131,6 +129,7 @@ static func enforce_capacity(world, target: Dictionary, rules: Dictionary, year: var excess: Variant = E.subtract(count, supported) if E.le(excess, 0): continue + changed = true var previous: String = (stages[E.subtract(index, 1)] if E.gt(index, 0) else "C1.9") world.batches.scale_batches(target, id, E.divide(supported, count)) target.amount[id] = supported @@ -161,79 +160,71 @@ static func enforce_capacity(world, target: Dictionary, rules: Dictionary, year: target.binds[owner] = {} target.binds[owner][previous] = E.add(target.binds[owner].get(previous, 0), amount) target.amount[previous] = E.subtract(target.amount[previous], amount) - physical = world.ledger.physical_amounts(target) - reconcile(world, target, rules, physical) + if changed: + physical = world.ledger.physical_amounts(target) + reconcile(world, target, rules, physical) assign_homes(world, target, rules, physical) + world.profile_end("enforce_capacity", profile_started) # Unity's structure chain: direct Claim resets the required structure count; # intervening stages require ten times more units of the preceding structure. static func habitat_budget(world, target: Dictionary, rules: Dictionary, physical: Dictionary = {}) -> Dictionary: if physical.is_empty(): physical = world.ledger.physical_amounts(target) - var structures: Array = [] + var layout: Dictionary = world.catalog.civilization_layout(rules) + var structures: Array = layout.structures var capacity: Dictionary = {} - for id in world.catalog.entities: - if E.ne(world.catalog.entities[id].claim, ""): - structures.append(id) - capacity[id] = physical.get(id, 0) - structures.sort_custom(func ( a , b ) : return (E.gt(world.catalog.entities[a].civ_bonus, world.catalog.entities[b].civ_bonus) if E.ne(world.catalog.entities[a].civ_bonus, world.catalog.entities[b].civ_bonus) else E.lt(str(a), str(b)))) - var stages: Array = [] - for id in rules: - if is_space_civilization(id, rules): stages.append(id) - stages.sort() - var requirements: Dictionary = {} - var anchors: Dictionary = {} - var anchor: String = "" - var units: Variant = 1 - for id in stages: - var direct: String = "" - for structure in structures: - if E.eq(world.catalog.entities[structure].claim, id): direct = structure - if E.ne(direct, ""): - anchor = direct - units = 1 - else: - units = E.multiply(units, 10) - anchors[id] = anchor - if (id.begins_with("C3.") or id.begins_with("C4.")): - requirements[id] = {"id": anchor, "units": units} + for id in structures: capacity[id] = physical.get(id, 0) + var requirements: Dictionary = layout.requirements + var anchors: Dictionary = layout.anchors var requested: Dictionary = {} for id in requirements: var req: Dictionary = requirements[id] requested[req.id] = E.add(requested.get(req.id, 0), E.multiply(physical.get(id, 0), req.units)) return {"capacity": capacity, "requested": requested, "requirements": requirements, "structures": structures, "anchors": anchors} +# A structure's direct reservation belongs only to its Claim stage. Other +# stages do not debit it, so each stage's placement can be calculated alone. +static func stage_homes(world, target: Dictionary, id: String, layout: Dictionary, capacity: Dictionary = {}) -> Dictionary: + var left: Variant = target.amount.get(id, 0) + var homes: Dictionary = {} + if E.le(left, 0): return homes + var allowed: bool = layout.anchors[id] == "" + for structure in layout.structures: + if structure == layout.anchors[id]: allowed = true + if not allowed: continue + var stock: Variant = capacity.get(structure, 0) if not capacity.is_empty() else world.ledger.physical_amount(target, structure) + if E.le(stock, 0): continue + var amount: Variant = left + if world.catalog.entities[structure].claim == id: + amount = E.minimum(amount, stock) + if E.gt(amount, 0): homes[structure] = amount + left = E.subtract(left, amount) + if E.le(left, 0): break + return homes + static func assign_homes(world, target: Dictionary, rules: Dictionary, physical: Dictionary = {}) -> void: - var budget: Dictionary = habitat_budget(world, target, rules, physical) - var used: Dictionary = {} + var profile_started: int = world.profile_start() + var layout: Dictionary = world.catalog.civilization_layout(rules) + var capacity: Dictionary = {} + for structure in layout.structures: + capacity[structure] = world.ledger.physical_amount(target, structure) if physical.is_empty() else physical.get(structure, 0) target.civilization_homes = {} - var stages: Array = budget.anchors.keys() - stages.sort() - stages.reverse() - for id in stages: - var left: Variant = target.amount.get(id, 0) - var homes: Dictionary = {} - var allowed: bool = E.eq(budget.anchors[id], "") - for structure in budget.structures: - if E.eq(structure, budget.anchors[id]): allowed = true - if ((not allowed) or E.le(budget.capacity[structure], 0)): continue - var amount: Variant = left - if E.eq(world.catalog.entities[structure].claim, id): - amount = E.minimum(amount, E.maximum(0, E.subtract(budget.capacity[structure], used.get(structure, 0)))) - used[structure] = E.add(used.get(structure, 0), amount) - if E.gt(amount, 0): homes[structure] = amount - left = E.subtract(left, amount) - if E.le(left, 0): break - target.civilization_homes[id] = homes + for index in range(layout.stages.size() - 1, -1, -1): + var id: String = layout.stages[index] + target.civilization_homes[id] = stage_homes(world, target, id, layout, capacity) + world.profile_end("assign_homes", profile_started) + static func effective_span(world, target: Dictionary, id: String, rules: Dictionary) -> Variant: if (not rules.has(id)): return world.catalog.entities[id].lifespan var base: Variant = rules[id].span if (not is_space_civilization(id, rules)): return base - assign_homes(world, target, rules) var population: Variant = target.amount.get(id, 0) if E.le(population, 0): return base + var homes: Dictionary = stage_homes(world, target, id, world.catalog.civilization_layout(rules)) + target.civilization_homes[id] = homes var weighted: Variant = population - for home in target.civilization_homes.get(id, {}): - weighted = E.add(weighted, E.multiply(target.civilization_homes[id][home], (E.subtract(E.maximum(0, world.catalog.entities[home].civ_bonus), 1)))) + for home in homes: + weighted = E.add(weighted, E.multiply(homes[home], (E.subtract(E.maximum(0, world.catalog.entities[home].civ_bonus), 1)))) return (E.mul_div(base, population, weighted) if E.gt(weighted, 0) else base) diff --git a/world/owniverse/entity_catalog.gd b/world/owniverse/entity_catalog.gd index e2d4c55..c6091f9 100644 --- a/world/owniverse/entity_catalog.gd +++ b/world/owniverse/entity_catalog.gd @@ -1,4 +1,5 @@ extends RefCounted +const E = preload("res://world/owniverse/math/exact.gd") ## Definitions and their indexes only: no population, batches or UI state. ## Definitions are Nodes owned by the caller, as before this extraction. @@ -8,7 +9,10 @@ var event_groups: Dictionary[String, Array] = {} var automatic_producers: Array = [] var unlockable_entities: Array = [] var _group_members: Dictionary = {} +var index_revision: int = 0 var _indexed_entity_count: int = -1 +var _civilization_layout: Dictionary = {} +var _civilization_rules: Dictionary = {} ## Populate an empty catalog; replacement uses a new catalog to preserve ownership. func load_definitions(rows: Dictionary) -> void: @@ -28,6 +32,8 @@ func load_definitions(rows: Dictionary) -> void: ## Call explicitly after modifying group_as without changing the entity count. func rebuild_group_index() -> void: + index_revision += 1 + _civilization_layout.clear() _group_members.clear() for id in entities: var group: String = entities[id].group_as @@ -45,3 +51,47 @@ func is_group(id: String) -> bool: func members(id: String) -> Array: if not is_group(id): return [id] return _group_members.get(id, []).duplicate() + +## Definition-only cache. Rebuild indexes after changing claims or bonuses; +## invalidate this layout after changing stage homes in an existing rules table. +func invalidate_civilization_layout() -> void: + _civilization_layout.clear() + +func civilization_layout(rules: Dictionary) -> Dictionary: + _ensure_group_index() + if not _civilization_layout.is_empty() and is_same(_civilization_rules, rules): + return _civilization_layout + _civilization_rules = rules + var structures: Array = [] + for id in entities: + if entities[id].claim != "": structures.append(id) + structures.sort_custom(func(a, b): return E.gt(entities[a].civ_bonus, entities[b].civ_bonus) if E.ne(entities[a].civ_bonus, entities[b].civ_bonus) else str(a) < str(b)) + var stages: Array = [] + for id in rules: + if str(rules[id].home) != "": stages.append(id) + stages.sort() + var anchors: Dictionary = {} + var requirements: Dictionary = {} + var anchor: String = "" + var units: Variant = 1 + for id in stages: + var direct: String = "" + for structure in structures: + if entities[structure].claim == id: direct = structure + if direct != "": + anchor = direct + units = 1 + else: + units = E.multiply(units, 10) + anchors[id] = anchor + if id.begins_with("C3.") or id.begins_with("C4."): + requirements[id] = {"id": anchor, "units": units} + var star_homes: Dictionary = {} + for id in entities: + var homes: Array = [] + for home in ["DwStar", "GiStar", "WD", "NS", "MGT", "BH"]: + if entities[id].event_group == home or entities[id].count_as == home or id == home: + homes.append(home) + if not homes.is_empty(): star_homes[id] = homes + _civilization_layout = {"structures": structures, "stages": stages, "anchors": anchors, "requirements": requirements, "star_homes": star_homes} + return _civilization_layout diff --git a/world/owniverse/evolution_coordinator.gd b/world/owniverse/evolution_coordinator.gd index 0f2f074..61197d7 100644 --- a/world/owniverse/evolution_coordinator.gd +++ b/world/owniverse/evolution_coordinator.gd @@ -19,12 +19,20 @@ func initialize_life_batches() -> void: world.batches.append_batch(world.state, id, E.maximum(0, E.subtract(physical.get(id, 0), tracked)), world.state.time.datetime, world.state.time.datetime) -func evolute_to_datetime(datetime: Variant, clock: Dictionary = {}) -> void: +func run_frame(clock: Dictionary, budget: RefCounted) -> void: + var _keep_alive: RefCounted = self + await evolute_to_datetime(clock.datetime, clock, budget) + if not budget.cancelled and world != null: world.finish_frame() + +func evolute_to_datetime(datetime: Variant, clock: Dictionary = {}, budget: RefCounted = null) -> void: + var _keep_alive: RefCounted = self # Reconcile only when simulation advances. # Fractional frame updates cannot change capacity or populations. var processed_year: Variant = SimulationTime.processed_year(datetime) if E.gt(processed_year, world.state.time.year): + var profile_initialize: int = world.profile_start() initialize_life_batches() + world.profile_end("initialize", profile_initialize) var previous: Dictionary = world.state var next: Dictionary = previous.duplicate_deep() next.version = SimulationTime.STATE_VERSION @@ -37,11 +45,21 @@ func evolute_to_datetime(datetime: Variant, clock: Dictionary = {}) -> void: var distribution: Dictionary = QuantityMath.normalize_distribution(quantities) next.distribution = distribution + var profile_production: int = world.profile_start() world.automatic.produce_for_period(previous, next, quantities, distribution, from_year, to_year) - evolve_batches(next, to_year) + world.profile_end("production", profile_production) + var profile_generations: int = world.profile_start() + if budget != null: + await evolve_batches(next, to_year, budget) + if budget.cancelled: return + else: + evolve_batches(next, to_year) + world.profile_end("generations", profile_generations) world.ledger.refresh_groups(next) world.ledger.clamp_auto_resources(next) + var profile_trends: int = world.profile_start() WorldParameters.advance(previous, next, Global.CivilizationRules, E.subtract(to_year, from_year)) + world.profile_end("trends", profile_trends) next.time = clock if not clock.is_empty() else {"datetime": datetime, "year": to_year} # Publish only after every phase has finished; previous stays untouched. @@ -50,16 +68,19 @@ func evolute_to_datetime(datetime: Variant, clock: Dictionary = {}) -> void: world.presentation.refresh(world.state, world.catalog) -func evolve_batches(target: Dictionary, to_year: Variant) -> void: +func evolve_batches(target: Dictionary, to_year: Variant, budget: RefCounted = null) -> void: + var _keep_alive: RefCounted = self # A long cycle may contain several generations; preserve actual birth intervals. var completed: Dictionary = {} - while evolve_batch_generation(target, to_year, completed): - pass + while await evolve_batch_generation(target, to_year, completed, budget): + if budget != null and not await budget.pause(): return -func evolve_batch_generation(target: Dictionary, to_year: Variant, completed: Dictionary = { }) -> bool: +func evolve_batch_generation(target: Dictionary, to_year: Variant, completed: Dictionary = { }, budget: RefCounted = null) -> bool: + var _keep_alive: RefCounted = self # Apply direct completions at the original next-generation boundary, so # binding transfers, the blast environment and capacity checks keep order. + if budget != null and not await budget.pause(): return false var completed_now: Dictionary = completed.duplicate(true) completed.clear() var quantities: Dictionary = world.ledger.physical_amounts(target) @@ -92,10 +113,12 @@ func evolve_batch_generation(target: Dictionary, to_year: Variant, completed: Di return false var fractions: Dictionary = {} var outputs: Dictionary = {} - var current_quantities: Dictionary = world.ledger.physical_amounts(target) + var current_quantities: Dictionary = quantities var star_budget: Dictionary = CivilizationState.stellar_budget(world, target, Global.CivilizationRules, current_quantities) - var civilization_transaction: Dictionary = CivilizationEvolution.prepare(world, target, expired, to_year, star_budget, Global.CivilizationRules, current_quantities) + var civilization_transaction: Dictionary = await CivilizationEvolution.prepare(world, target, expired, to_year, star_budget, Global.CivilizationRules, current_quantities, budget) + if budget != null and budget.cancelled: return false for id in expired: + if budget != null and not await budget.pause(): return false var total: Variant = 0 for part : Dictionary in expired[id]: total = E.add(total, part.amount) @@ -127,6 +150,7 @@ func evolve_batch_generation(target: Dictionary, to_year: Variant, completed: Di for id in expired: for part : Dictionary in expired[id]: for successor in part.products: + if budget != null and not await budget.pause(): return false var amount: Variant = part.products[successor] if E.eq(successor, "blast"): blast_power = E.add(blast_power, amount) @@ -137,15 +161,28 @@ func evolve_batch_generation(target: Dictionary, to_year: Variant, completed: Di target.amount[id] = E.add(target.amount.get(id, 0), amount) else: amount = world.ledger.credit(target, successor, amount) - var before_batches: Array = target.batches.get(successor, []).duplicate(true) + var produces: bool = not world.automatic.yearly_products(world.catalog.entities[successor]).is_empty() + var before_batches: Array = target.batches.get(successor, []).duplicate(true) if produces else [] var cutoff: Variant = (to_year if world.stellar.uses_short_lived_fast_path(successor) else E.neg(INF)) - var integral: Variant = world.batches.append_batch(target, successor, amount, part.from, part.to, completed, cutoff) - world.automatic.produce_newborn_lifetime(target, successor, amount, part.from, part.to, to_year, before_batches, integral) + var profile_newborn: int = world.profile_start() + var integral: Variant + if budget != null: + integral = await world.batches.append_batch(target, successor, amount, part.from, part.to, completed, cutoff, budget) + if budget.cancelled: return false + else: + integral = world.batches.append_batch(target, successor, amount, part.from, part.to, completed, cutoff) + if produces: + world.automatic.produce_newborn_lifetime(target, successor, amount, part.from, part.to, to_year, before_batches, integral) + world.profile_end("newborn_batches", profile_newborn) new_owners[successor] = E.add(new_owners.get(successor, 0), amount) world.ledger.accept_transfers(target, incoming) world.ledger.bind_new_owners(target, new_owners) world.ledger.round_object_allocations(target) - CivilizationEvolution.finish(world, target, civilization_transaction, to_year, Global.CivilizationRules) + if budget != null: + await CivilizationEvolution.finish(world, target, civilization_transaction, to_year, Global.CivilizationRules, budget) + if budget.cancelled: return false + else: + CivilizationEvolution.finish(world, target, civilization_transaction, to_year, Global.CivilizationRules) world.stellar.apply_blast(target, blast_power, environment) CivilizationState.enforce_capacity(world, target, Global.CivilizationRules, to_year) return true diff --git a/world/owniverse/frame_budget.gd b/world/owniverse/frame_budget.gd new file mode 100644 index 0000000..5eeb77e --- /dev/null +++ b/world/owniverse/frame_budget.gd @@ -0,0 +1,22 @@ +extends RefCounted +## Cooperative work on the main thread. No partially calculated state is published. +var tree: SceneTree +var slice_usec: int = 40000 +var deadline: int +var cancelled: bool = false +var waiting_usec: int = 0 + +func _init(scene_tree: SceneTree, milliseconds: int = 40): + tree = scene_tree + slice_usec = milliseconds * 1000 + deadline = Time.get_ticks_usec() + slice_usec + +func pause() -> bool: + var keep_alive: RefCounted = self + if cancelled: return false + if Time.get_ticks_usec() >= deadline: + var waiting_from: int = Time.get_ticks_usec() + await tree.process_frame + keep_alive.waiting_usec += Time.get_ticks_usec() - waiting_from + deadline = Time.get_ticks_usec() + slice_usec + return not keep_alive.cancelled diff --git a/world/owniverse/frame_budget.gd.uid b/world/owniverse/frame_budget.gd.uid new file mode 100644 index 0000000..d2ef99d --- /dev/null +++ b/world/owniverse/frame_budget.gd.uid @@ -0,0 +1 @@ +uid://hu57pwad02sg diff --git a/world/owniverse/item_description.gd b/world/owniverse/item_description.gd index 3128e29..80a8c1b 100644 --- a/world/owniverse/item_description.gd +++ b/world/owniverse/item_description.gd @@ -8,7 +8,7 @@ const Parameters = preload("res://world/owniverse/world_parameters.gd") static func number(value, digits: int = 0) -> String: if not E.finite(value): return "—" - return E.scientific(value, 4) if E.ge(E.absolute(value), 100000) else E.fixed(value, digits) + return E.grouped(value, digits, false) static func colored(text: String, color: String) -> String: return E.add(E.add(E.add(E.add("[color=", color), "]"), text), "[/color]") diff --git a/world/owniverse/math/README.md b/world/owniverse/math/README.md index 2a84155..46330f8 100644 --- a/world/owniverse/math/README.md +++ b/world/owniverse/math/README.md @@ -1,101 +1,43 @@ # Числа симуляции -`exact.gd` сохраняет единый API `E` для симуляции и интерфейса. Целые числа, -помещающиеся в `int64`, остаются обычными `int`. Остальные значения хранятся -в `exact_value.gd`: +Целые значения в диапазоне int64 хранятся как `int`. Остальные числа имеют вид +`polarity × (sum(whole[i] × 10^(9i)) + fraction)`: +`whole` — динамический массив целых блоков по основанию 10^9, +`fraction` — float от 0 включительно до 1 исключительно. Числа после создания +не изменяются. Ограничения E27 в хранении нет; размер массива растёт по необходимости. -``` -polarity × (high × 10^14 + low + fraction) -``` +Используйте API `E.add/subtract/multiply/divide`, `E.eq/lt/le/gt/ge` и +`E.floor_value/ceil_value/round_value`. Обычные операторы над ExactValue не работают. +`E.integer` требует значения в диапазоне int64; `E.approx` явно преобразует +число в float и для очень больших чисел возвращает бесконечность. +Сравнение через E сохраняет отличие конечного большого числа от INF. -`high` и `low` — целые блоки от 0 до 10^14−1, `fraction` — `float` от 0 до 1, -`polarity` — знак. Значения неизменяемы после создания. Диапазон включает весь -порядок E27: модуль целой части меньше 10^28. Каждая единица целой части -сохраняется, в том числе при добавлении и вычитании единицы около 10^27. -Выход за диапазон проверяется утверждениями; насыщения или обрезания запасов нет. +Целые операции выполняются точно. Умножение и деление используют безопасные +разряды из `big_integer.gd`; нативная арифметика применяется при отсутствии +переполнения int64. `E.mul_div(count, numerator, denominator)` сохраняет точное +целое частное, не превращая заранее отношение в приближённый коэффициент. +`E.floor_sum` суммирует округлённые линейные квоты без перебора каждого окна. -Числители и знаменатели в состоянии больше не хранятся. НОД при обычных -арифметических операциях не вычисляется; обход состояния для ограничения дробей -больше не нужен. `bounded` и `bound_state` оставлены как совместимые пустые операции. +Дробный остаток приблизительный: при умножении и делении он преобразуется +в десятичную дробь с 16 значащими цифрами. При сложении двух ненулевых остатков +перенос около целой границы стабилизируется с допуском 10^-12. +Умножение большого количества на float усиливает ошибку коэффициента; +для известных точных отношений используйте mul_div. Целые распределения +и сохранение числа объектов проверяются строго, без допуска. -## Операции +Возраст сохраняет точную целую часть. Только дробная часть переводится в +наносекундные тики, дополнительный остаток времени переносится между кадрами. +Синхронный диагностический API evolute отклоняет шаги от 1e27 игровых лет: +это защита от непрактичного интервала, а не предел хранимого возраста. +Покадровый API ограничивает одну транзакцию обычным шагом 1/60 секунды; +остальное запрошенное время остаётся в очереди. -Сложение, вычитание и сравнение работают непосредственно с блоками. -Деление int64 и объединённое умножение/деление при безопасном произведении -используют нативную арифметику. Перевод больших целых между блоками и временными -разрядами, извлечение коэффициента и сборка результата обходятся без строк. -Дробный коэффициент нормализуется численно до 16 значащих цифр; последние биты -float могут отличаться от результата прежнего строкового преобразования. -Для умножения и деления `big_integer.gd` используется как временный вычислитель -с безопасными разрядами по основанию 10^9. Результат сразу возвращается в -фиксированную структуру. Размер временных дробей определяется входными float, -а не растёт от шага к шагу. +Формат сохранения — **5**, версия состояния — **0.3.0**. +Большие целые и числа с дробью кодируются как +`{"$exact": [[blocks], "float bytes in hex", sign]}`. +Байты остатка сохраняются без потери точности JSON. Миграции старых форматов нет. -`E.mul_div(a, b, denominator)` вычисляет отношение за одну операцию. Это нужно -для распределений: произведение двух количеств может превышать E27, хотя итог -деления укладывается в диапазон. Промежуточное произведение не становится -значением симуляции. Целое частное вычисляется до перевода остатка в float. - -```gdscript -const E = preload("res://world/owniverse/math/exact.gd") -var stock = E.of("1e27") # Большое целое вводится строкой. -stock = E.subtract(stock, 1) -var share = E.mul_div(stock, 15, 100) # Точные 15% целого запаса. -var whole_share = E.floor_value(share) -``` - -Использовать `E.add/subtract/multiply/divide`, `E.eq/lt/le/gt/ge`, -`E.floor_value/ceil_value/round_value`. Обычные операторы над объектами -`ExactValue` не подходят. `E.integer` допускается только для значений int64; -`E.approx` — явный переход к приближённому float. - -## Дробная точность - -Дробная часть приближённая. Для временного умножения/деления она преобразуется -в десятичную дробь с 16 значащими цифрами; нормализация сохраняет значащие цифры -малых коэффициентов. Десятичные стоимости вроде 0.125 и 0.0000000000001 -сохраняют корректный размер производственной партии. НОД применяется только -при определении знаменателя стоимости в `production_step`. - -При сложении двух ненулевых дробных частей перенос около целой границы -стабилизируется с допуском 10^-12. Это предотвращает задержку редких событий -из-за накопленной ошибки float. Допуск не применяется к целым блокам или -округлению частного при делении. Суммы распределённых целых объектов проверяются -строго, без допуска. - -При умножении большого количества на приближённый коэффициент ошибка самого -коэффициента усиливается: float-доля не обещает точности результата до единицы. -Известные точные отношения нужно передавать через `mul_div(count, numerator, -denominator)`, не вычисляя коэффициент заранее. - -Возраст хранится как целые годы и дробный остаток; в наносекундные тики -переводится только дробная часть года. Полный возраст больше не умножается на -10^9. Остаток кадрового времени переносится отдельно. Геометрический объём -пустот может превышать E27 из-за множителя 10^22: он вычисляется в float и -используется только для приближённых коэффициентов плотности и бластов. - -Форматирование не создаёт больших промежуточных значений симуляции: например, -округлённая подпись `1.00E+28` допустима для количества чуть меньше 10^28. - -## Сохранение - -Формат сохранения — **4**, версия состояния — **0.3.0**. Большие целые -кодируются как `{"$exact": "целое число"}`. Блоки с дробью кодируются как -`{"$fixed": ["high", "low", "float bytes in hex", sign]}`. Восемь байтов float -сохраняются без потери точности JSON, включая очень малые остатки. -Зашифрованный файл и диагностический JSON используют один снимок. - -Миграции нет. Сохранение прежнего формата при обычной загрузке архивируется -существующим механизмом `.incompatible.bak`; начинается новая игра. -Тесты не загружают и не перезаписывают рабочее сохранение игрока. - -## Проверки - -`godot --headless --path Owniverse.GI --script res://tests/test_exact_math.gd` - -Независимый эталон `tests/fixtures/exact_oracle.json` получен через Python -`fractions.Fraction` (160 пар, seed 4321). Произведения находятся внутри E27; -дробные результаты сравниваются с абсолютным допуском 10^-12, целые — точно. -Дополнительно проверяются границы int64/E27, единичные изменения, точные -проценты, объединённое умножение с делением, JSON, дробные рецепты, -распределения, жизнь, энергия, время, форматирование и 100 циклов симуляции. +Проверки: `test_exact_math.gd`, `test_dynamic_math.gd`, `test_quantity_catalog.gd`, +`test_time.gd` и `test_frame_evolution.gd`. Независимый целочисленный эталон +покрывает числа до 220 десятичных цифр; отдельные проверки — до E1000, +границы int64, доли, сериализацию, распределения и продолжение расчёта. diff --git a/world/owniverse/math/big_integer.gd b/world/owniverse/math/big_integer.gd index bd3631b..c500c1f 100644 --- a/world/owniverse/math/big_integer.gd +++ b/world/owniverse/math/big_integer.gd @@ -102,3 +102,26 @@ static func gcd(a: Array, b: Array) -> Array: a = b b = remainder return a + +## Sum floor((a*i+b)/m), i=0..n-1, using Euclidean reduction. +## All arguments are unsigned; no loop over the number of time windows. +static func floor_sum(n: Array, m: Array, a: Array, b: Array) -> Array: + var result: Array = [0] + while n != [0]: + var qr: Array = divmod(a, m) + if qr[0] != [0]: + var pairs: Array = divmod(multiply(n, subtract(n, [1])), [2])[0] + result = add(result, multiply(pairs, qr[0])) + a = qr[1] + qr = divmod(b, m) + result = add(result, multiply(n, qr[0])) + b = qr[1] + var upper: Array = add(multiply(a, n), b) + if compare(upper, m) < 0: break + qr = divmod(upper, m) + n = qr[0] + b = qr[1] + var temporary: Array = m + m = a + a = temporary + return result diff --git a/world/owniverse/math/exact.gd b/world/owniverse/math/exact.gd index e1d8566..cd7e416 100644 --- a/world/owniverse/math/exact.gd +++ b/world/owniverse/math/exact.gd @@ -1,27 +1,45 @@ extends RefCounted -## Fixed whole blocks and a float remainder. Native integers are the fast path. +## Dynamic whole blocks and a float remainder. Native integers are the fast path. const Big = preload("res://world/owniverse/math/big_integer.gd") const Value = preload("res://world/owniverse/math/exact_value.gd") const SMALL: int = 1000000000 const MAX_INT: int = 9223372036854775807 const MIN_INT: int = -9223372036854775807 - 1 -const BLOCK: int = 100000000000000 # 10^14 -const LIMIT: Array = [0, 0, 0, 10] # 10^28, exclusive +const MAX_INT_LIMBS: Array = [854775807, 223372036, 9] +const MIN_INT_LIMBS: Array = [854775808, 223372036, 9] -static func max_value(): - return make([999999999, 999999999, 9999]) +static func _int_limbs(value: int) -> Array: + var result: Array = [] + while value != 0: + result.append(absi(value % SMALL)) + value /= SMALL + return result if not result.is_empty() else [0] -static func make(n: Array, d: Array = [1], polarity: int = 1): - assert(d != [0], "Zero denominator") - if n.size() <= 2 and d.size() <= 2: - var numerator: int = n[0] + (n[1] * SMALL if n.size() == 2 else 0) - var denominator: int = d[0] + (d[1] * SMALL if d.size() == 2 else 0) - var whole: int = numerator / denominator - var fraction: float = minf(float(numerator % denominator) / float(denominator), 1.0 - pow(2.0, -53)) - return _compose(whole / BLOCK, whole % BLOCK, fraction, polarity) - var qr: Array = Big.divmod(n, d) - var fraction: float = _fraction_ratio(qr[1], d) - return _from_whole(qr[0], fraction, polarity) +static func _compose(whole: Array, fraction: float = 0.0, polarity: int = 1): + whole = Big.trim(whole.duplicate()) + if fraction >= 1.0: + var carry: float = floorf(fraction) + whole = Big.add(whole, Big.parse("%.0f" % carry)) + fraction -= carry + elif fraction < 0.0: + assert(Big.compare(whole, [0]) > 0, "Negative magnitude") + whole = Big.subtract(whole, [1]) + fraction += 1.0 + if fraction >= 1.0: + whole = Big.add(whole, [1]) + fraction = 0.0 + if whole == [0] and fraction == 0.0: + return 0 + if fraction == 0.0 and Big.compare(whole, MAX_INT_LIMBS) <= 0: + var magnitude: int = int(whole[0]) + (int(whole[1]) * SMALL if whole.size() > 1 else 0) + (int(whole[2]) * 1000000000000000000 if whole.size() > 2 else 0) + return magnitude * (-1 if polarity < 0 else 1) + if fraction == 0.0 and polarity < 0 and Big.compare(whole, MIN_INT_LIMBS) == 0: + return MIN_INT + var result = Value.new() + result.whole = whole + result.fraction = minf(fraction, 1.0 - pow(2.0, -53)) + result.polarity = -1 if polarity < 0 else 1 + return result static func _fraction_ratio(n: Array, d: Array) -> float: if n == [0]: return 0.0 @@ -36,57 +54,15 @@ static func _fraction_ratio(n: Array, d: Array) -> float: fraction *= pow(10.0, mini(0, exponent + 308)) return minf(fraction, 1.0 - pow(2.0, -53)) -static func _from_whole(n: Array, fraction: float, polarity: int): - assert(Big.compare(n, LIMIT) < 0, "Number exceeds E27 range") - var middle: int = n[1] if n.size() > 1 else 0 - var low: int = n[0] + (middle % 100000) * SMALL - var high: int = middle / 100000 - if n.size() > 2: high += n[2] * 10000 - if n.size() > 3: high += n[3] * 10000000000000 - return _compose(high, low, fraction, polarity) - -static func _whole_limbs(high: int, low: int) -> Array: - return Big.trim([low % SMALL, low / SMALL + (high % 10000) * 100000, - (high / 10000) % SMALL, high / 10000000000000]) - -static func _int_limbs(value: int) -> Array: - var result: Array = [] - # Modulo/division before abs also supports MIN_INT. - while value != 0: - result.append(absi(value % SMALL)) - value /= SMALL - return result if not result.is_empty() else [0] - -static func _compose(high: int, low: int, fraction: float, polarity: int): - if fraction >= 1.0: - low += int(floorf(fraction)) - fraction -= floorf(fraction) - if fraction < 0.0: - low -= 1 - fraction += 1.0 - if low >= BLOCK: - high += low / BLOCK - low %= BLOCK - elif low < 0: - high -= 1 - low += BLOCK - assert(high >= 0 and high < BLOCK, "Number exceeds E27 range") - if fraction == 0.0 and high <= 92233: - var prefix: int = high * BLOCK - if low <= MAX_INT - prefix: return polarity * (prefix + low) - if polarity < 0 and low == MAX_INT - prefix + 1: return MIN_INT - var result = Value.new() - result.high = high - result.low = low - result.fraction = fraction - result.polarity = polarity - return result +static func make(n: Array, d: Array = [1], polarity: int = 1): + assert(d != [0], "Zero denominator") + var qr: Array = Big.divmod(n, d) + return _compose(qr[0], _fraction_ratio(qr[1], d), polarity) static func _blocks(value) -> Array: value = of(value) - if value is Value: return [value.high, value.low, value.fraction, value.polarity] - # Signed division also handles MIN_INT without overflowing abs(). - return [absi(value / BLOCK), absi(value % BLOCK), 0.0, -1 if value < 0 else 1] + if value is Value: return [value.whole, value.fraction, value.polarity] + return [_int_limbs(value), 0.0, -1 if value < 0 else 1] static func of(value): if value is Value or value is int: return value @@ -94,7 +70,7 @@ static func of(value): if not is_finite(value): return value if value == floorf(value) and absf(value) < 1e18: return int(value) var magnitude: float = absf(value) - return _from_whole(Big.parse("%.0f" % floorf(magnitude)), magnitude - floorf(magnitude), -1 if value < 0 else 1) + return _compose(Big.parse("%.0f" % floorf(magnitude)), magnitude - floorf(magnitude), -1 if value < 0 else 1) var text: String = str(value).strip_edges().to_lower() if text == "": return 0 if "/" in text: @@ -114,25 +90,16 @@ static func of(value): return make(Big.parse(text + "0".repeat(maxi(0, power))), Big.parse("1" + "0".repeat(maxi(0, -power))), polarity) static func parts(value) -> Array: - value = of(value) - if value is int: return [_int_limbs(value), [1], -1 if value < 0 else 1] - var whole: Array = _whole_limbs(value.high, value.low) - if value.fraction == 0.0: return [whole, [1], value.polarity] - # Bound temporary decimal work to 16 significant digits of the float. - # Normalize first so tiny rates retain their significant digits as well. - var exponent: int = maxi(-323, int(floor(log(value.fraction) / log(10.0)))) - var mantissa: int = roundi((value.fraction / pow(10.0, exponent)) * 1000000000000000.0) + var x: Array = _blocks(value) + if x[1] == 0.0: return [x[0], [1], x[2]] + var exponent: int = maxi(-323, int(floor(log(x[1]) / log(10.0)))) + var mantissa: int = roundi((x[1] / pow(10.0, exponent)) * 1000000000000000.0) exponent -= 15 while mantissa % 10 == 0 and mantissa > 0: mantissa /= 10 exponent += 1 - var n: Array = _int_limbs(mantissa) - var d: Array = [] - d.resize((-exponent) / 9 + 1) - d.fill(0) - const POWERS: Array = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000] - d[d.size() - 1] = POWERS[(-exponent) % 9] - return [Big.add(Big.multiply(whole, d), n), d, value.polarity] + var denominator: Array = Big.parse("1" + "0".repeat(-exponent)) + return [Big.add(Big.multiply(x[0], denominator), _int_limbs(mantissa)), denominator, x[2]] static func numeric(value) -> bool: return value is int or value is float or value is Value @@ -142,20 +109,28 @@ static func finite(value) -> bool: static func approx(value) -> float: if not value is Value: return float(value) - return value.polarity * (float(value.high) * BLOCK + float(value.low) + value.fraction) + if value.whole == [0]: return value.polarity * value.fraction + var start: int = maxi(0, value.whole.size() - 3) + var leading: float = 0.0 + for i in range(value.whole.size() - 1, start - 1, -1): leading = leading * SMALL + value.whole[i] + var exponent: int = start * 9 + if exponent > 308: return INF * value.polarity + return value.polarity * (leading * pow(10.0, exponent) + value.fraction) static func compare(a, b) -> int: if a is int and b is int: return 0 if a == b else (1 if a > b else -1) if not finite(a) or not finite(b): + if finite(a): return -1 if b > 0 else 1 + if finite(b): return 1 if a > 0 else -1 var x: float = approx(a) var y: float = approx(b) return 0 if x == y else (1 if x > y else -1) var x: Array = _blocks(a) var y: Array = _blocks(b) - if x[3] != y[3]: return 1 if x[3] > y[3] else -1 - for i in 3: - if x[i] != y[i]: return x[3] * (1 if x[i] > y[i] else -1) - return 0 + if x[2] != y[2]: return 1 if x[2] > y[2] else -1 + var magnitude: int = Big.compare(x[0], y[0]) + if magnitude == 0 and x[1] != y[1]: magnitude = 1 if x[1] > y[1] else -1 + return magnitude * x[2] static func eq(a, b) -> bool: if a == null: return b == null @@ -186,7 +161,11 @@ static func ge(a, b) -> bool: return compare(a, b) >= 0 if numeric(a) and numeri static func minimum(a, b): return a if le(a, b) else b static func maximum(a, b): return a if ge(a, b) else b static func clamp_value(a, low, high): return minimum(maximum(a, low), high) -static func neg(a): return subtract(0, a) +static func neg(a): + if not numeric(a): return -a + if a is int: return -a if a != MIN_INT else _compose(_int_limbs(a), 0.0, 1) + if a is float: return -a + return _compose(a.whole, a.fraction, -a.polarity) static func absolute(a): return neg(a) if lt(a, 0) else a static func add(a, b): @@ -196,32 +175,24 @@ static func add(a, b): if not finite(a) or not finite(b): return approx(a) + approx(b) var x: Array = _blocks(a) var y: Array = _blocks(b) - if x[3] == y[3]: - var fraction: float = x[2] + y[2] - # Repeated fractional accumulation may land just below an integer. - # This tolerance only applies to the fractional carry, never whole blocks. - if x[2] > 0.0 and y[2] > 0.0 and fraction > 0.5 and absf(fraction - roundf(fraction)) <= 1e-12: - fraction = roundf(fraction) - return _compose(x[0] + y[0], x[1] + y[1], fraction, x[3]) - var order: int = 0 - for i in 3: - if x[i] != y[i]: - order = 1 if x[i] > y[i] else -1 - break + if x[2] == y[2]: + var fraction: float = x[1] + y[1] + if x[1] > 0.0 and y[1] > 0.0 and fraction > 0.5 and absf(fraction - roundf(fraction)) <= 1e-12: fraction = roundf(fraction) + return _compose(Big.add(x[0], y[0]), fraction, x[2]) + var order: int = Big.compare(x[0], y[0]) + if order == 0 and x[1] != y[1]: order = 1 if x[1] > y[1] else -1 if order == 0: return 0 if order < 0: - var tmp: Array = x + var temporary: Array = x x = y - y = tmp - return _compose(x[0] - y[0], x[1] - y[1], x[2] - y[2], x[3]) + y = temporary + return _compose(Big.subtract(x[0], y[0]), x[1] - y[1], x[2]) static func subtract(a, b): if not numeric(a) or not numeric(b): return a - b if a is int and b is int: if (b >= 0 and a >= MIN_INT + b) or (b < 0 and a <= MAX_INT + b): return a - b - if not finite(a) or not finite(b): return approx(a) - approx(b) - var y: Array = _blocks(b) - return add(a, _compose(y[0], y[1], y[2], -y[3])) + return add(a, neg(b)) static func multiply(a, b): if not numeric(a) or not numeric(b): return a * b @@ -246,6 +217,18 @@ static func mul_div(a, b, divisor): assert(z[0] != [0], "Division by zero") return make(Big.multiply(Big.multiply(x[0], y[0]), z[1]), Big.multiply(Big.multiply(x[1], y[1]), z[0]), x[2] * y[2] * z[2]) +## Sum of nonnegative linear quotas rounded down separately at each boundary. +static func floor_sum(count, step, offset, divisor): + var n: Array = parts(count) + var a: Array = parts(step) + var b: Array = parts(offset) + var d: Array = parts(divisor) + assert(n[1] == [1] and n[2] > 0 and a[2] > 0 and b[2] > 0 and d[2] > 0 and d[0] != [0]) + var numerator_step: Array = Big.multiply(Big.multiply(a[0], b[1]), d[1]) + var numerator_offset: Array = Big.multiply(Big.multiply(b[0], a[1]), d[1]) + var denominator: Array = Big.multiply(Big.multiply(a[1], b[1]), d[0]) + return make(Big.floor_sum(n[0], denominator, numerator_step, numerator_offset)) + static func divide(a, b): if not numeric(a) or not numeric(b): return a / b if not finite(a) or not finite(b): return approx(a) / approx(b) @@ -257,7 +240,7 @@ static func divide(a, b): var denominator: int = absi(b) var whole: int = numerator / denominator var fraction: float = minf(float(numerator % denominator) / float(denominator), 1.0 - pow(2.0, -53)) - return _compose(whole / BLOCK, whole % BLOCK, fraction, -1 if (a < 0) != (b < 0) else 1) + return _compose(_int_limbs(whole), fraction, -1 if (a < 0) != (b < 0) else 1) var x: Array = parts(a) var y: Array = parts(b) assert(y[0] != [0], "Division by zero") @@ -266,7 +249,7 @@ static func divide(a, b): static func floor_value(a): if not finite(a) or a is int: return a var x: Array = _blocks(a) - return _compose(x[0], x[1] + (1 if x[3] < 0 and x[2] > 0 else 0), 0.0, x[3]) + return _compose(Big.add(x[0], [1]) if x[2] < 0 and x[1] > 0.0 else x[0], 0.0, x[2]) static func ceil_value(a): return neg(floor_value(neg(a))) static func round_value(a): return multiply(-1 if lt(a, 0) else 1, floor_value(add(absolute(a), of("0.5")))) @@ -274,8 +257,14 @@ static func remainder(a, b): return subtract(a, multiply(truncate(divide(a, b)), static func truncate(a): return ceil_value(a) if lt(a, 0) else floor_value(a) static func integer(a) -> int: var result = truncate(of(a)) - assert(result is int, "Value does not fit native int64") - return result + if result is int: return result + if result is Value and result.fraction == 0.0: + if result.polarity < 0 and Big.compare(result.whole, MIN_INT_LIMBS) == 0: return MIN_INT + if Big.compare(result.whole, MAX_INT_LIMBS) <= 0: + var magnitude: int = int(result.whole[0]) + (int(result.whole[1]) * SMALL if result.whole.size() > 1 else 0) + (int(result.whole[2]) * 1000000000000000000 if result.whole.size() > 2 else 0) + return magnitude * result.polarity + assert(false, "Value does not fit native int64") + return 0 ## Kept as no-op API: float remainder storage is already bounded. static func bounded(value): return value @@ -283,15 +272,18 @@ static func bounded(value): return value static func bound_state(value): return value static func power(a, b): - if finite(b) and lt(b, 0): return of(pow(approx(a), approx(b))) if finite(b) and eq(b, floor_value(b)) and le(absolute(b), 10000): + # Small negative powers retain the native float precision; huge bases + # need block arithmetic because approx(base) can become infinity. + if lt(b, 0) and is_finite(approx(a)): + return of(pow(approx(a), approx(b))) var exponent: int = integer(absolute(b)) var result = 1 while exponent: if exponent % 2: result = multiply(result, a) exponent /= 2 if exponent: a = multiply(a, a) - return result + return divide(1, result) if lt(b, 0) else result return coefficient(pow(approx(a), approx(b))) static func coefficient(value: float): @@ -299,8 +291,24 @@ static func coefficient(value: float): if not is_finite(value): return value return of(String.num(value, 12)) -static func square_root(a): return coefficient(sqrt(approx(a))) -static func logarithm(a): return coefficient(log(approx(a))) +static func square_root(a): + var approximate: float = approx(a) + if is_finite(approximate): return coefficient(sqrt(approximate)) + if a is Value and a.polarity > 0: + var exponent: int = (Big.decimal(a.whole).length() - 1) / 2 + var scale = of("1e%d" % exponent) + var reduced = divide(a, multiply(scale, scale)) + return multiply(coefficient(sqrt(approx(reduced))), scale) + return coefficient(sqrt(approximate)) +static func logarithm(a): + var approximate: float = approx(a) + if is_finite(approximate): return coefficient(log(approximate)) + if a is Value and a.polarity > 0: + var start: int = maxi(0, a.whole.size() - 3) + var leading: float = 0.0 + for i in range(a.whole.size() - 1, start - 1, -1): leading = leading * SMALL + a.whole[i] + return coefficient(log(leading) + start * 9 * log(10.0)) + return coefficient(log(approximate)) static func near(a, b) -> bool: return le(absolute(subtract(a, b)), multiply(of("0.00001"), maximum(1, maximum(absolute(a), absolute(b))))) @@ -337,9 +345,9 @@ static func scientific(value, digits: int = 4) -> String: exponent += 1 return fixed(mantissa, digits) + ("E+%d" if exponent >= 0 else "E%d") % exponent -static func grouped(value, digits: int = 0) -> String: - if eq(value, 0): return "" - if ge(absolute(value), 1000000000): return scientific(value, digits) +static func grouped(value, digits: int = 0, compact: bool = true) -> String: + if eq(value, 0): return "" if compact else fixed(0, digits) + if compact and ge(absolute(value), 1000000000): return scientific(value, digits) var text: String = fixed(absolute(value), digits) var parts_text: PackedStringArray = text.split(".") var integer_text: String = parts_text[0] @@ -350,16 +358,15 @@ static func grouped(value, digits: int = 0) -> String: return ("-" if lt(value, 0) else "") + integer_text + result + ("." + parts_text[1] if parts_text.size() > 1 else "") static func encode(value): - if value is Value: + if value is Value or (value is int and (value > 9007199254740991 or value < -9007199254740991)): + var blocks: Array = _blocks(value) var bytes := PackedByteArray() bytes.resize(8) - bytes.encode_double(0, value.fraction) - return {"$fixed": [str(value.high), str(value.low), bytes.hex_encode(), value.polarity]} - if value is int and (value > 9007199254740991 or value < -9007199254740991): - return {"$exact": str(value)} + bytes.encode_double(0, blocks[1]) + return {"$exact": [blocks[0], bytes.hex_encode(), blocks[2]]} if value is Dictionary: var result: Dictionary = {} - for k in value: result[k] = encode(value[k]) + for key in value: result[key] = encode(value[key]) return result if value is Array: var result: Array = [] @@ -369,12 +376,11 @@ static func encode(value): static func decode(value): if value is Dictionary: - if value.size() == 1 and value.has("$fixed"): - var fields: Array = value["$fixed"] - return _compose(int(fields[0]), int(fields[1]), fields[2].hex_decode().decode_double(0), int(fields[3])) - if value.size() == 1 and value.has("$exact"): return of(value["$exact"]) + if value.size() == 1 and value.has("$exact"): + var fields: Array = value["$exact"] + return _compose(fields[0], fields[1].hex_decode().decode_double(0), int(fields[2])) var result: Dictionary = {} - for k in value: result[k] = decode(value[k]) + for key in value: result[key] = decode(value[key]) return result if value is Array: var result: Array = [] @@ -385,30 +391,19 @@ static func decode(value): static func valid_encoded(value) -> bool: if value is float: return is_finite(value) and absf(value) < 1e28 if value is Dictionary: - if value.has("$fixed"): - if value.size() != 1 or not value["$fixed"] is Array: return false - var fields: Array = value["$fixed"] - if fields.size() != 4: return false - for i in 2: - if not fields[i] is String or not fields[i].is_valid_int() or fields[i].length() > 14: return false - if int(fields[i]) < 0 or int(fields[i]) >= BLOCK: return false - if not fields[2] is String or fields[2].length() != 16 or not fields[2].is_valid_hex_number(): return false - var fraction: float = fields[2].hex_decode().decode_double(0) - return is_finite(fraction) and fraction >= 0.0 and fraction < 1.0 and fields[3] in [-1, 1] + if value.has("$fixed"): return false if value.has("$exact"): - if value.size() != 1 or not value["$exact"] is String: return false - var text: String = value["$exact"] - if text.length() > 29: return false - var terms: PackedStringArray = text.split("/") - if terms.size() != 1: return false - var n: String = terms[0].trim_prefix("-") - if n.is_empty(): return false - for ch in n: - if ch < "0" or ch > "9": return false - if Big.compare(Big.parse(n), LIMIT) >= 0: return false - return true - for k in value: - if not valid_encoded(value[k]): return false + if value.size() != 1 or not value["$exact"] is Array: return false + var fields: Array = value["$exact"] + if fields.size() != 3 or not fields[0] is Array or not fields[1] is String or not fields[2] in [-1, 1]: return false + if fields[0].is_empty() or (fields[0].size() > 1 and fields[0].back() == 0): return false + if fields[1].length() != 16 or not fields[1].is_valid_hex_number(): return false + for limb in fields[0]: + if not limb is int or limb < 0 or limb >= SMALL: return false + var fraction: float = fields[1].hex_decode().decode_double(0) + return is_finite(fraction) and fraction >= 0.0 and fraction < 1.0 + for key in value: + if not valid_encoded(value[key]): return false if value is Array: for item in value: if not valid_encoded(item): return false diff --git a/world/owniverse/math/exact_value.gd b/world/owniverse/math/exact_value.gd index 388e39f..2a85470 100644 --- a/world/owniverse/math/exact_value.gd +++ b/world/owniverse/math/exact_value.gd @@ -1,11 +1,12 @@ extends RefCounted -## Immutable magnitude high * 10^14 + low + fraction, with a separate sign. +## Immutable signed magnitude: whole is little-endian base 1e9 blocks. var polarity: int = 1 -var high: int = 0 -var low: int = 0 +var whole: Array = [0] var fraction: float = 0.0 func _to_string() -> String: - var whole: String = str(high) + "%014d" % low if high else str(low) + var whole_text: String = str(whole.back()) + for i in range(whole.size() - 2, -1, -1): + whole_text += "%09d" % whole[i] var tail: String = String.num(fraction, 16).trim_prefix("0").trim_suffix(".") if fraction else "" - return ("-" if polarity < 0 else "") + whole + tail + return ("-" if polarity < 0 else "") + whole_text + tail diff --git a/world/owniverse/object_batches.gd b/world/owniverse/object_batches.gd index 8430c83..7bc2656 100644 --- a/world/owniverse/object_batches.gd +++ b/world/owniverse/object_batches.gd @@ -34,7 +34,8 @@ func scale_batches(target: Dictionary, id: String, factor: Variant) -> void: share.batch.withdraw_remainder = E.minimum(share.batch.get("withdraw_remainder", 0), share.batch.amount) -func append_batch(target: Dictionary, id: String, amount: Variant, created_from: Variant, created_to: Variant, completed: Dictionary = { }, completed_before: Variant = - INF) -> Variant: +func append_batch(target: Dictionary, id: String, amount: Variant, created_from: Variant, created_to: Variant, completed: Dictionary = { }, completed_before: Variant = - INF, budget: RefCounted = null) -> Variant: + var _keep_alive: RefCounted = self if ((E.le(amount, 0) or (not world.catalog.entities.has(id))) or E.le(world.catalog.entities[id].lifespan, 0)): return NAN if E.lt(created_to, created_from): @@ -67,12 +68,46 @@ func append_batch(target: Dictionary, id: String, amount: Variant, created_from: window_index = E.add(window_index, 1) var batches_by_start: Dictionary = {} var skip_empty_expired: bool = E.gt(duration, 0) and E.finite(completed_before) and E.eq(amount, E.floor_value(amount)) + var sparse_windows: bool = E.gt(duration, 0) and E.gt(amount, 0) and E.gt(duration, E.multiply(batch_duration, amount)) and not skip_empty_expired for existing : Dictionary in batches: var start: Variant = existing.get("created_from", E.neg(INF)) if (not batches_by_start.has(str(start))): batches_by_start[str(start)] = [] batches_by_start[str(start)].append(existing) while true: + if budget != null and not await budget.pause(): return NAN + # A zero cohort is discarded by withdraw_batches. Jump straight to the + # first boundary whose cumulative whole quota increases, rather than + # allocating and later removing hundreds of empty dictionaries. + if sparse_windows: + var threshold: Variant = E.add(created_from, E.mul_div(duration, E.add(E.subtract(amount, remaining_amount), 1), amount)) + var next_nonempty: Variant = E.subtract(E.ceil_value(E.divide(E.subtract(threshold, origin), batch_duration)), 1) + if E.gt(next_nonempty, window_index): + window_index = next_nonempty + cursor = E.maximum(created_from, E.add(origin, E.multiply(window_index, batch_duration))) + if skip_empty_expired: + var completed_end_index = E.floor_value(E.divide(E.subtract(E.minimum(created_to, E.subtract(completed_before, lifespan)), origin), batch_duration)) + var window_count = E.subtract(completed_end_index, window_index) + if E.gt(window_count, 1): + var first_start = E.add(origin, E.multiply(window_index, batch_duration)) + var first_end = E.add(first_start, batch_duration) + var last_end = E.add(origin, E.multiply(completed_end_index, batch_duration)) + var last_quota = E.floor_value(E.mul_div(amount, E.subtract(last_end, created_from), duration)) + var total_completed = E.subtract(last_quota, E.subtract(amount, remaining_amount)) + # Summation by parts preserves every per-window floor. Its + # weighted sum gives the same lifetime production integral. + var preceding_quotas = E.floor_sum(E.subtract(window_count, 1), E.multiply(amount, batch_duration), E.multiply(amount, E.subtract(first_end, created_from)), duration) + var weighted_windows = E.subtract(E.multiply(E.subtract(window_count, 1), last_quota), preceding_quotas) + var first_expired_years = E.subtract(E.subtract(completed_before, E.add(first_start, lifespan)), E.divide(batch_duration, 2)) + var expired_integral = E.subtract(E.multiply(total_completed, first_expired_years), E.multiply(batch_duration, weighted_windows)) + remaining_object_years = E.subtract(remaining_object_years, expired_integral) + completed_amount = E.add(completed_amount, total_completed) + completed_from = E.minimum(completed_from, E.add(first_start, lifespan)) + completed_to = E.maximum(completed_to, E.add(last_end, lifespan)) + remaining_amount = E.subtract(remaining_amount, total_completed) + window_index = completed_end_index + cursor = last_end + if E.ge(cursor, created_to): break # Whole allocation changes only when its cumulative quota reaches the # next integer. Skip expired empty windows without changing the span # passed to the next generation or the lifetime production integral. diff --git a/world/owniverse/object_ledger.gd b/world/owniverse/object_ledger.gd index 91b09c0..9453b4c 100644 --- a/world/owniverse/object_ledger.gd +++ b/world/owniverse/object_ledger.gd @@ -3,7 +3,16 @@ const E = preload("res://world/owniverse/math/exact.gd") const CivilizationState = preload("res://world/owniverse/civilization_state.gd") const QuantityMath = preload("res://world/owniverse/quantity_math.gd") +var _amount_snapshot: Dictionary = {} +var _binds_snapshot: Dictionary = {} +var _physical_cache: Dictionary = {} +var _physical_revision: int = -1 + func physical_amounts(source: Dictionary) -> Dictionary: + world.catalog._ensure_group_index() + if _physical_revision == world.catalog.index_revision and source.amount == _amount_snapshot and source.binds == _binds_snapshot: + return _physical_cache.duplicate() + var profile_started: int = world.profile_start() var amounts: Dictionary = {} for id in world.catalog.entities: if (not world.catalog.is_group(id)): @@ -12,7 +21,12 @@ func physical_amounts(source: Dictionary) -> Dictionary: for id in bindings: if amounts.has(id): amounts[id] = E.add(amounts[id], E.maximum(0, bindings[id])) - return amounts + _amount_snapshot = source.amount.duplicate() + _binds_snapshot = source.binds.duplicate(true) + _physical_cache = amounts + _physical_revision = world.catalog.index_revision + world.profile_end("physical_amounts_build", profile_started) + return amounts.duplicate() func physical_amount(source: Dictionary, id: String) -> Variant: diff --git a/world/owniverse/owniverse.gd b/world/owniverse/owniverse.gd index 94222bb..1f335aa 100644 --- a/world/owniverse/owniverse.gd +++ b/world/owniverse/owniverse.gd @@ -14,6 +14,19 @@ var stellar = preload("res://world/owniverse/stellar_rules.gd").new(self) var life = preload("res://world/owniverse/life_evolution.gd").new(self) var environment = preload("res://world/owniverse/universe_environment.gd").new(self) var evolution = preload("res://world/owniverse/evolution_coordinator.gd").new(self) +var profile_enabled: bool = false +var profile: Dictionary = {} + +func profile_start() -> int: + if not profile_enabled: return 0 + return Time.get_ticks_usec() - (frame_budget.waiting_usec if frame_busy and frame_budget != null else 0) + +func profile_end(section: String, started: int) -> void: + if not profile_enabled: return + var sample: Array = profile.get(section, [0, 0]) + sample[0] += profile_start() - started + sample[1] += 1 + profile[section] = sample var state: Dictionary = { 'version': SimulationTime.STATE_VERSION, @@ -44,10 +57,78 @@ var state: Dictionary = { 'stats': {'total_amount': {}}, } +var frame_busy: bool = false +var frame_commits: int = 0 +var frame_clock: Dictionary = {} +var frame_budget: RefCounted +var _requested_speed: int = 0 +var _queued_productions: Array = [] +var frame_active_clock: Dictionary = {} +var _resume_clock: Dictionary = {} + +## Keep the requested clock advancing while a transaction spans render frames. +func evolute_frame(delta: float, tree: SceneTree) -> void: + if not is_finite(delta) or delta < 0.0 or not is_finite(delta * pow(10.0, speed - 1)): return + if frame_clock.is_empty(): frame_clock = state.time.duplicate() + frame_clock = SimulationTime.advance(frame_clock, delta, speed) + if frame_busy: return + if E.le(frame_clock.datetime, state.time.datetime) and _resume_clock.is_empty(): return + frame_busy = true + frame_budget = preload("res://world/owniverse/frame_budget.gd").new(tree) + frame_active_clock = _resume_clock if not _resume_clock.is_empty() else frame_clock.duplicate() + # Keep each transaction at the normal 60 Hz simulation interval. The + # requested clock holds the backlog, rather than feeding an ever-growing + # multi-generation interval into one transaction and freezing publication. + if _resume_clock.is_empty(): + var normal_clock: Dictionary = SimulationTime.advance(state.time, 1.0 / 60.0, speed) + if E.lt(normal_clock.datetime, frame_clock.datetime): + frame_active_clock = normal_clock + _resume_clock = {} + evolution.run_frame(frame_active_clock, frame_budget) + +func request_production(id: String, amount: Variant, resource: bool = false) -> void: + if frame_busy: + _queued_productions.append({"id": id, "amount": amount, "resource": resource}) + elif resource: + production.produce_hs(id, amount) + else: + production.produce(id, amount) + +## Persist work requests, never the partially calculated transaction. +func frame_checkpoint() -> Dictionary: + return {"requested_clock": frame_clock, "active_clock": frame_active_clock if frame_busy else {}, "speed": speed, "productions": _queued_productions} + +func restore_frame_checkpoint(checkpoint: Dictionary) -> void: + frame_clock = checkpoint.get("requested_clock", {}) + _resume_clock = checkpoint.get("active_clock", {}) + _queued_productions = checkpoint.get("productions", []) + if _resume_clock.is_empty(): + speed = checkpoint.get("speed", state.speed) + else: + _requested_speed = checkpoint.get("speed", state.speed) + +func finish_frame() -> void: + frame_busy = false + frame_commits += 1 + if _requested_speed != 0: + speed = _requested_speed + _requested_speed = 0 + var productions: Array = _queued_productions + _queued_productions = [] + for command in productions: + request_production(command.id, command.amount, command.resource) + +func _notification(what: int) -> void: + if what == NOTIFICATION_PREDELETE and frame_budget != null: + frame_budget.cancelled = true + var speed: int : get: - return state.speed + return _requested_speed if _requested_speed != 0 else state.speed set(value): + if frame_busy: + _requested_speed = clampi(value, 1, Global.SPEED_LIMIT) + return state.speed = clampi(value, 1, Global.SPEED_LIMIT) state.speed_in_year = E.power(10, E.subtract(state.speed, 1)) diff --git a/world/owniverse/quantity_math.gd b/world/owniverse/quantity_math.gd index 0844074..fc2f4c7 100644 --- a/world/owniverse/quantity_math.gd +++ b/world/owniverse/quantity_math.gd @@ -12,24 +12,32 @@ static func accumulate_whole(target: Dictionary, field: String, key: String, val static func allocate_whole(requests: Dictionary, limit: Variant) -> Dictionary: - var total: Variant = 0 - for amount in requests.values(): - total = E.add(total, E.floor_value(E.maximum(0, amount))) - var available: Variant = E.floor_value(E.minimum(E.maximum(0, limit), total)) var result: Dictionary = {} + var total: Variant = 0 + for id in requests: + result[id] = E.floor_value(E.maximum(0, requests[id])) + total = E.add(total, result[id]) + var available: Variant = E.floor_value(E.minimum(E.maximum(0, limit), total)) + # No apportionment or rounding is necessary when every request fits. + if E.eq(available, total): return result + if E.le(available, 0): + for id in result: result[id] = 0 + return result + var ids: Array = requests.keys() + var rests: Array = [] var order: Array = [] var assigned: Variant = 0 - for id in requests: - var expected: Variant = (E.mul_div(E.floor_value(E.maximum(0, requests[id])), available, total) if E.gt(total, 0) else 0) - result[id] = E.floor_value(expected) - assigned = E.add(assigned, result[id]) - order.append({"id": id, "rest": E.subtract(expected, result[id])}) - order.sort_custom(func ( a : Dictionary , b : Dictionary ) -> bool : return (E.gt(a.rest, b.rest) if E.ne(a.rest, b.rest) else E.lt(str(a.id), str(b.id)))) - for item : Dictionary in order: - if E.ge(assigned, available): - break - if E.lt(result[item.id], E.floor_value(requests[item.id])): - result[item.id] = E.add(result[item.id], 1) + for i in ids.size(): + var expected: Variant = E.mul_div(result[ids[i]], available, total) + result[ids[i]] = E.floor_value(expected) + assigned = E.add(assigned, result[ids[i]]) + rests.append(E.subtract(expected, result[ids[i]])) + order.append(i) + order.sort_custom(func(a: int, b: int) -> bool: return E.gt(rests[a], rests[b]) if E.ne(rests[a], rests[b]) else str(ids[a]) < str(ids[b])) + for i in order: + if E.ge(assigned, available): break + if E.lt(result[ids[i]], E.floor_value(requests[ids[i]])): + result[ids[i]] = E.add(result[ids[i]], 1) assigned = E.add(assigned, 1) return result @@ -74,25 +82,32 @@ static func split(remainders: Dictionary, key: String, count: Variant, weights: var result: Dictionary = {} var sum_weights: Variant = sum(weights) if (E.le(count, 0) or E.le(sum_weights, 0)): return result - var expected: Dictionary = {} + var ids: Array = weights.keys() + var expected: Array = [] + var remainder_keys: Array = [] var positive_sum: Variant = 0 - for id in weights: - expected[id] = E.add(E.mul_div(count, weights[id], sum_weights), remainders.get(E.add(E.add(key, ":"), id), 0)) - positive_sum = E.add(positive_sum, E.maximum(0, expected[id])) + for id in ids: + var remainder_key: String = key + ":" + str(id) + remainder_keys.append(remainder_key) + var value: Variant = E.add(E.mul_div(count, weights[id], sum_weights), remainders.get(remainder_key, 0)) + expected.append(value) + positive_sum = E.add(positive_sum, E.maximum(0, value)) var order: Array = [] + var rests: Array = [] var assigned: Variant = 0 - for id in weights: - var normalized: Variant = (E.mul_div(E.maximum(0, expected[id]), count, positive_sum) if E.gt(positive_sum, 0) else 0) - result[id] = E.floor_value(normalized) - assigned = E.add(assigned, result[id]) - order.append({"id": id, "rest": E.subtract(normalized, result[id])}) - order.sort_custom(func ( a , b ) : return (E.gt(a.rest, b.rest) if E.ne(a.rest, b.rest) else E.lt(str(a.id), str(b.id)))) - for entry in order: + for i in ids.size(): + var normalized: Variant = E.mul_div(E.maximum(0, expected[i]), count, positive_sum) if E.gt(positive_sum, 0) else 0 + result[ids[i]] = E.floor_value(normalized) + assigned = E.add(assigned, result[ids[i]]) + rests.append(E.subtract(normalized, result[ids[i]])) + order.append(i) + order.sort_custom(func(a: int, b: int) -> bool: return E.gt(rests[a], rests[b]) if E.ne(rests[a], rests[b]) else str(ids[a]) < str(ids[b])) + for i in order: if E.ge(assigned, count): break - result[entry.id] = E.add(result[entry.id], 1) + result[ids[i]] = E.add(result[ids[i]], 1) assigned = E.add(assigned, 1) - for id in weights: - remainders[E.add(E.add(key, ":"), id)] = E.clamp_value(E.subtract(expected[id], result[id]), E.neg(1), 1) + for i in ids.size(): + remainders[remainder_keys[i]] = E.clamp_value(E.subtract(expected[i], result[ids[i]]), E.neg(1), 1) return result diff --git a/world/owniverse/universe_environment.gd b/world/owniverse/universe_environment.gd index cda315c..a5ddb30 100644 --- a/world/owniverse/universe_environment.gd +++ b/world/owniverse/universe_environment.gd @@ -21,6 +21,18 @@ func stellar_environment(source: Dictionary) -> Dictionary: if E.gt(mass, 0): metallicity = E.maximum(0, E.add(E.multiply(E.of("0.4"), E.logarithm(E.add(E.mul_div(100, source.amount.get("Met", 0), mass), E.of("0.11")))), E.of("0.88"))) var base_mass: Variant = E.multiply(65536, ((E.power(mass, E.of("0.1")) if (E.gt(mass, 0) and E.lt(mass, E.of("1.0e10"))) else ((10 if E.ge(mass, E.of("1.0e10")) else 1))))) + if not is_finite(volume) or not is_finite(E.approx(E.add(base_mass, mass))): + # Dynamic counts may exceed the float exponent range. Evaluate the + # same geometry using logarithms, avoiding infinity / infinity. + var exact_volume: Variant = quantities.get("S", 0) + for id in quantities: + var entity: OwniverseEntity = world.catalog.entities[id] + var size: Variant = E.add(E.maximum(0, entity.space), E.multiply(E.maximum(0, entity.voids), E.of("1e22"))) + exact_volume = E.add(exact_volume, E.multiply(quantities[id], size)) + var density_log: float = log(1.23456e-7) + E.approx(E.logarithm(E.add(base_mass, mass))) / 2.0 - E.approx(E.logarithm(E.maximum(1, exact_volume))) / 6.0 + var density: Variant = E.of("1e%d" % int(floor(density_log / log(10.0)))) + density = E.multiply(density, E.coefficient(exp(density_log - floor(density_log / log(10.0)) * log(10.0)))) + return {"metallicity": metallicity, "density": density, "blast": E.clamp_value(E.divide(source.amount.get("S", 0), exact_volume), 0, 1) if E.gt(exact_volume, 0) else 1} return {"metallicity": metallicity, "density": E.coefficient(1.23456e-7 * sqrt(E.approx(E.add(base_mass, mass))) / pow(maxf(1.0, volume), 1.0 / 6.0)), "blast": E.coefficient(clampf(E.approx(source.amount.get("S", 0)) / volume, 0.0, 1.0)) if volume > 0.0 else 1} diff --git a/world/owniverse/world_parameters.gd b/world/owniverse/world_parameters.gd index 7e7a203..26a6711 100644 --- a/world/owniverse/world_parameters.gd +++ b/world/owniverse/world_parameters.gd @@ -65,8 +65,9 @@ static func advance(previous: Dictionary, target: Dictionary, rules: Dictionary, for n in population.values(): count = E.add(count, n) if E.gt(count, 0): for ethic in population: + var proportion: Variant = E.divide(population[ethic], count) for i in TRENDS.size(): - rates[i] = E.add(rates[i], E.multiply(E.multiply(E.divide(population[ethic], count), WEIGHTS[ethic][i]), weight)) + rates[i] = E.add(rates[i], E.multiply(E.multiply(proportion, WEIGHTS[ethic][i]), weight)) weight = E.multiply(weight, 2) for i in TRENDS.size(): var name: String = TRENDS[i] @@ -84,7 +85,14 @@ static func _integration(target: Dictionary, events: Variant) -> void: var rng = RandomNumberGenerator.new() rng.seed = 76123 if target.civilization_stats.has("trend_rng"): - rng.state = E.integer(target.civilization_stats.trend_rng) + # Godot exposes the generator state as an unsigned 64-bit value. The + # arithmetic layer intentionally stores values above int64 as blocks; + # convert its bit pattern back to the signed integer accepted by the + # RNG setter after loading. + var saved_state: Variant = target.civilization_stats.trend_rng + if E.gt(saved_state, 9223372036854775807): + saved_state = E.subtract(saved_state, E.of("18446744073709551616")) + rng.state = E.integer(saved_state) var counts: Array = [0, 0, 0] if E.le(events, 256): for i in E.integer(events):