crca 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- .github/ISSUE_TEMPLATE/bug_report.md +65 -0
- .github/ISSUE_TEMPLATE/feature_request.md +41 -0
- .github/PULL_REQUEST_TEMPLATE.md +20 -0
- .github/workflows/publish-manual.yml +61 -0
- .github/workflows/publish.yml +64 -0
- .gitignore +214 -0
- CRCA.py +4156 -0
- LICENSE +201 -0
- MANIFEST.in +43 -0
- PKG-INFO +5035 -0
- README.md +4959 -0
- __init__.py +17 -0
- branches/CRCA-Q.py +2728 -0
- branches/crca_cg/corposwarm.py +9065 -0
- branches/crca_cg/fix_rancher_docker_creds.ps1 +155 -0
- branches/crca_cg/package.json +5 -0
- branches/crca_cg/test_bolt_integration.py +446 -0
- branches/crca_cg/test_corposwarm_comprehensive.py +773 -0
- branches/crca_cg/test_new_features.py +163 -0
- branches/crca_sd/__init__.py +149 -0
- branches/crca_sd/crca_sd_core.py +770 -0
- branches/crca_sd/crca_sd_governance.py +1325 -0
- branches/crca_sd/crca_sd_mpc.py +1130 -0
- branches/crca_sd/crca_sd_realtime.py +1844 -0
- branches/crca_sd/crca_sd_tui.py +1133 -0
- crca-1.4.0.dist-info/METADATA +5035 -0
- crca-1.4.0.dist-info/RECORD +501 -0
- crca-1.4.0.dist-info/WHEEL +4 -0
- crca-1.4.0.dist-info/licenses/LICENSE +201 -0
- docs/CRCA-Q.md +2333 -0
- examples/config.yaml.example +25 -0
- examples/crca_sd_example.py +513 -0
- examples/data_broker_example.py +294 -0
- examples/logistics_corporation.py +861 -0
- examples/palantir_example.py +299 -0
- examples/policy_bench.py +934 -0
- examples/pridnestrovia-sd.py +705 -0
- examples/pridnestrovia_realtime.py +1902 -0
- prompts/__init__.py +10 -0
- prompts/default_crca.py +101 -0
- pyproject.toml +151 -0
- requirements.txt +76 -0
- schemas/__init__.py +43 -0
- schemas/mcpSchemas.py +51 -0
- schemas/policy.py +458 -0
- templates/__init__.py +38 -0
- templates/base_specialized_agent.py +195 -0
- templates/drift_detection.py +325 -0
- templates/examples/causal_agent_template.py +309 -0
- templates/examples/drag_drop_example.py +213 -0
- templates/examples/logistics_agent_template.py +207 -0
- templates/examples/trading_agent_template.py +206 -0
- templates/feature_mixins.py +253 -0
- templates/graph_management.py +442 -0
- templates/llm_integration.py +194 -0
- templates/module_registry.py +276 -0
- templates/mpc_planner.py +280 -0
- templates/policy_loop.py +1168 -0
- templates/prediction_framework.py +448 -0
- templates/statistical_methods.py +778 -0
- tests/sanity.yml +31 -0
- tests/sanity_check +406 -0
- tests/test_core.py +47 -0
- tests/test_crca_excel.py +166 -0
- tests/test_crca_sd.py +780 -0
- tests/test_data_broker.py +424 -0
- tests/test_palantir.py +349 -0
- tools/__init__.py +38 -0
- tools/actuators.py +437 -0
- tools/bolt.diy/Dockerfile +103 -0
- tools/bolt.diy/app/components/@settings/core/AvatarDropdown.tsx +175 -0
- tools/bolt.diy/app/components/@settings/core/ControlPanel.tsx +345 -0
- tools/bolt.diy/app/components/@settings/core/constants.tsx +108 -0
- tools/bolt.diy/app/components/@settings/core/types.ts +114 -0
- tools/bolt.diy/app/components/@settings/index.ts +12 -0
- tools/bolt.diy/app/components/@settings/shared/components/TabTile.tsx +151 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionForm.tsx +193 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionTestIndicator.tsx +60 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ErrorState.tsx +102 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/LoadingState.tsx +94 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ServiceHeader.tsx +72 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/index.ts +6 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataTab.tsx +721 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataVisualization.tsx +384 -0
- tools/bolt.diy/app/components/@settings/tabs/event-logs/EventLogsTab.tsx +1013 -0
- tools/bolt.diy/app/components/@settings/tabs/features/FeaturesTab.tsx +295 -0
- tools/bolt.diy/app/components/@settings/tabs/github/GitHubTab.tsx +281 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubAuthDialog.tsx +173 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubCacheManager.tsx +367 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubConnection.tsx +233 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubErrorBoundary.tsx +105 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubProgressiveLoader.tsx +266 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositoryCard.tsx +121 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositorySelector.tsx +312 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubStats.tsx +291 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubUserProfile.tsx +46 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/GitHubStateIndicators.tsx +264 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/RepositoryCard.tsx +361 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/index.ts +11 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/GitLabTab.tsx +305 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabAuthDialog.tsx +186 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabConnection.tsx +253 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabRepositorySelector.tsx +358 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryCard.tsx +79 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryList.tsx +142 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/StatsDisplay.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/index.ts +4 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerList.tsx +99 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerListItem.tsx +70 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpStatusBadge.tsx +37 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpTab.tsx +239 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/NetlifyTab.tsx +1393 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/NetlifyConnection.tsx +990 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/tabs/notifications/NotificationsTab.tsx +300 -0
- tools/bolt.diy/app/components/@settings/tabs/profile/ProfileTab.tsx +181 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/cloud/CloudProvidersTab.tsx +308 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ErrorBoundary.tsx +68 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/HealthStatusBadge.tsx +64 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LoadingSkeleton.tsx +107 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +556 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ModelCard.tsx +106 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ProviderCard.tsx +120 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/SetupGuide.tsx +671 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/StatusDashboard.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/types.ts +44 -0
- tools/bolt.diy/app/components/@settings/tabs/settings/SettingsTab.tsx +215 -0
- tools/bolt.diy/app/components/@settings/tabs/supabase/SupabaseTab.tsx +1089 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/VercelTab.tsx +909 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/VercelConnection.tsx +368 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/utils/tab-helpers.ts +54 -0
- tools/bolt.diy/app/components/chat/APIKeyManager.tsx +169 -0
- tools/bolt.diy/app/components/chat/Artifact.tsx +296 -0
- tools/bolt.diy/app/components/chat/AssistantMessage.tsx +192 -0
- tools/bolt.diy/app/components/chat/BaseChat.module.scss +47 -0
- tools/bolt.diy/app/components/chat/BaseChat.tsx +522 -0
- tools/bolt.diy/app/components/chat/Chat.client.tsx +670 -0
- tools/bolt.diy/app/components/chat/ChatAlert.tsx +108 -0
- tools/bolt.diy/app/components/chat/ChatBox.tsx +334 -0
- tools/bolt.diy/app/components/chat/CodeBlock.module.scss +10 -0
- tools/bolt.diy/app/components/chat/CodeBlock.tsx +85 -0
- tools/bolt.diy/app/components/chat/DicussMode.tsx +17 -0
- tools/bolt.diy/app/components/chat/ExamplePrompts.tsx +37 -0
- tools/bolt.diy/app/components/chat/FilePreview.tsx +38 -0
- tools/bolt.diy/app/components/chat/GitCloneButton.tsx +327 -0
- tools/bolt.diy/app/components/chat/ImportFolderButton.tsx +141 -0
- tools/bolt.diy/app/components/chat/LLMApiAlert.tsx +109 -0
- tools/bolt.diy/app/components/chat/MCPTools.tsx +129 -0
- tools/bolt.diy/app/components/chat/Markdown.module.scss +171 -0
- tools/bolt.diy/app/components/chat/Markdown.spec.ts +48 -0
- tools/bolt.diy/app/components/chat/Markdown.tsx +252 -0
- tools/bolt.diy/app/components/chat/Messages.client.tsx +102 -0
- tools/bolt.diy/app/components/chat/ModelSelector.tsx +797 -0
- tools/bolt.diy/app/components/chat/NetlifyDeploymentLink.client.tsx +51 -0
- tools/bolt.diy/app/components/chat/ProgressCompilation.tsx +110 -0
- tools/bolt.diy/app/components/chat/ScreenshotStateManager.tsx +33 -0
- tools/bolt.diy/app/components/chat/SendButton.client.tsx +39 -0
- tools/bolt.diy/app/components/chat/SpeechRecognition.tsx +28 -0
- tools/bolt.diy/app/components/chat/StarterTemplates.tsx +38 -0
- tools/bolt.diy/app/components/chat/SupabaseAlert.tsx +199 -0
- tools/bolt.diy/app/components/chat/SupabaseConnection.tsx +339 -0
- tools/bolt.diy/app/components/chat/ThoughtBox.tsx +43 -0
- tools/bolt.diy/app/components/chat/ToolInvocations.tsx +409 -0
- tools/bolt.diy/app/components/chat/UserMessage.tsx +101 -0
- tools/bolt.diy/app/components/chat/VercelDeploymentLink.client.tsx +158 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ExportChatButton.tsx +49 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ImportButtons.tsx +96 -0
- tools/bolt.diy/app/components/deploy/DeployAlert.tsx +197 -0
- tools/bolt.diy/app/components/deploy/DeployButton.tsx +277 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploymentDialog.tsx +1041 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploymentDialog.tsx +764 -0
- tools/bolt.diy/app/components/deploy/NetlifyDeploy.client.tsx +246 -0
- tools/bolt.diy/app/components/deploy/VercelDeploy.client.tsx +235 -0
- tools/bolt.diy/app/components/editor/codemirror/BinaryContent.tsx +7 -0
- tools/bolt.diy/app/components/editor/codemirror/CodeMirrorEditor.tsx +555 -0
- tools/bolt.diy/app/components/editor/codemirror/EnvMasking.ts +80 -0
- tools/bolt.diy/app/components/editor/codemirror/cm-theme.ts +192 -0
- tools/bolt.diy/app/components/editor/codemirror/indent.ts +68 -0
- tools/bolt.diy/app/components/editor/codemirror/languages.ts +112 -0
- tools/bolt.diy/app/components/git/GitUrlImport.client.tsx +147 -0
- tools/bolt.diy/app/components/header/Header.tsx +42 -0
- tools/bolt.diy/app/components/header/HeaderActionButtons.client.tsx +54 -0
- tools/bolt.diy/app/components/mandate/MandateSubmission.tsx +167 -0
- tools/bolt.diy/app/components/observability/DeploymentStatus.tsx +168 -0
- tools/bolt.diy/app/components/observability/EventTimeline.tsx +119 -0
- tools/bolt.diy/app/components/observability/FileDiffViewer.tsx +121 -0
- tools/bolt.diy/app/components/observability/GovernanceStatus.tsx +197 -0
- tools/bolt.diy/app/components/observability/GovernorMetrics.tsx +246 -0
- tools/bolt.diy/app/components/observability/LogStream.tsx +244 -0
- tools/bolt.diy/app/components/observability/MandateDetails.tsx +201 -0
- tools/bolt.diy/app/components/observability/ObservabilityDashboard.tsx +200 -0
- tools/bolt.diy/app/components/sidebar/HistoryItem.tsx +187 -0
- tools/bolt.diy/app/components/sidebar/Menu.client.tsx +536 -0
- tools/bolt.diy/app/components/sidebar/date-binning.ts +59 -0
- tools/bolt.diy/app/components/txt +1 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/index.tsx +18 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/styles.module.scss +246 -0
- tools/bolt.diy/app/components/ui/Badge.tsx +53 -0
- tools/bolt.diy/app/components/ui/BranchSelector.tsx +270 -0
- tools/bolt.diy/app/components/ui/Breadcrumbs.tsx +101 -0
- tools/bolt.diy/app/components/ui/Button.tsx +46 -0
- tools/bolt.diy/app/components/ui/Card.tsx +55 -0
- tools/bolt.diy/app/components/ui/Checkbox.tsx +32 -0
- tools/bolt.diy/app/components/ui/CloseButton.tsx +49 -0
- tools/bolt.diy/app/components/ui/CodeBlock.tsx +103 -0
- tools/bolt.diy/app/components/ui/Collapsible.tsx +9 -0
- tools/bolt.diy/app/components/ui/ColorSchemeDialog.tsx +378 -0
- tools/bolt.diy/app/components/ui/Dialog.tsx +449 -0
- tools/bolt.diy/app/components/ui/Dropdown.tsx +63 -0
- tools/bolt.diy/app/components/ui/EmptyState.tsx +154 -0
- tools/bolt.diy/app/components/ui/FileIcon.tsx +346 -0
- tools/bolt.diy/app/components/ui/FilterChip.tsx +92 -0
- tools/bolt.diy/app/components/ui/GlowingEffect.tsx +192 -0
- tools/bolt.diy/app/components/ui/GradientCard.tsx +100 -0
- tools/bolt.diy/app/components/ui/IconButton.tsx +84 -0
- tools/bolt.diy/app/components/ui/Input.tsx +22 -0
- tools/bolt.diy/app/components/ui/Label.tsx +20 -0
- tools/bolt.diy/app/components/ui/LoadingDots.tsx +27 -0
- tools/bolt.diy/app/components/ui/LoadingOverlay.tsx +32 -0
- tools/bolt.diy/app/components/ui/PanelHeader.tsx +20 -0
- tools/bolt.diy/app/components/ui/PanelHeaderButton.tsx +36 -0
- tools/bolt.diy/app/components/ui/Popover.tsx +29 -0
- tools/bolt.diy/app/components/ui/Progress.tsx +22 -0
- tools/bolt.diy/app/components/ui/RepositoryStats.tsx +87 -0
- tools/bolt.diy/app/components/ui/ScrollArea.tsx +41 -0
- tools/bolt.diy/app/components/ui/SearchInput.tsx +80 -0
- tools/bolt.diy/app/components/ui/SearchResultItem.tsx +134 -0
- tools/bolt.diy/app/components/ui/Separator.tsx +22 -0
- tools/bolt.diy/app/components/ui/SettingsButton.tsx +35 -0
- tools/bolt.diy/app/components/ui/Slider.tsx +73 -0
- tools/bolt.diy/app/components/ui/StatusIndicator.tsx +90 -0
- tools/bolt.diy/app/components/ui/Switch.tsx +37 -0
- tools/bolt.diy/app/components/ui/Tabs.tsx +52 -0
- tools/bolt.diy/app/components/ui/TabsWithSlider.tsx +112 -0
- tools/bolt.diy/app/components/ui/ThemeSwitch.tsx +29 -0
- tools/bolt.diy/app/components/ui/Tooltip.tsx +122 -0
- tools/bolt.diy/app/components/ui/index.ts +38 -0
- tools/bolt.diy/app/components/ui/use-toast.ts +66 -0
- tools/bolt.diy/app/components/workbench/DiffView.tsx +796 -0
- tools/bolt.diy/app/components/workbench/EditorPanel.tsx +174 -0
- tools/bolt.diy/app/components/workbench/ExpoQrModal.tsx +55 -0
- tools/bolt.diy/app/components/workbench/FileBreadcrumb.tsx +150 -0
- tools/bolt.diy/app/components/workbench/FileTree.tsx +565 -0
- tools/bolt.diy/app/components/workbench/Inspector.tsx +126 -0
- tools/bolt.diy/app/components/workbench/InspectorPanel.tsx +146 -0
- tools/bolt.diy/app/components/workbench/LockManager.tsx +262 -0
- tools/bolt.diy/app/components/workbench/PortDropdown.tsx +91 -0
- tools/bolt.diy/app/components/workbench/Preview.tsx +1049 -0
- tools/bolt.diy/app/components/workbench/ScreenshotSelector.tsx +293 -0
- tools/bolt.diy/app/components/workbench/Search.tsx +257 -0
- tools/bolt.diy/app/components/workbench/Workbench.client.tsx +506 -0
- tools/bolt.diy/app/components/workbench/terminal/Terminal.tsx +131 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalManager.tsx +68 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalTabs.tsx +277 -0
- tools/bolt.diy/app/components/workbench/terminal/theme.ts +36 -0
- tools/bolt.diy/app/components/workflow/WorkflowPhase.tsx +109 -0
- tools/bolt.diy/app/components/workflow/WorkflowStatus.tsx +60 -0
- tools/bolt.diy/app/components/workflow/WorkflowTimeline.tsx +150 -0
- tools/bolt.diy/app/entry.client.tsx +7 -0
- tools/bolt.diy/app/entry.server.tsx +80 -0
- tools/bolt.diy/app/root.tsx +156 -0
- tools/bolt.diy/app/routes/_index.tsx +175 -0
- tools/bolt.diy/app/routes/api.bug-report.ts +254 -0
- tools/bolt.diy/app/routes/api.chat.ts +463 -0
- tools/bolt.diy/app/routes/api.check-env-key.ts +41 -0
- tools/bolt.diy/app/routes/api.configured-providers.ts +110 -0
- tools/bolt.diy/app/routes/api.corporate-swarm-status.ts +55 -0
- tools/bolt.diy/app/routes/api.enhancer.ts +137 -0
- tools/bolt.diy/app/routes/api.export-api-keys.ts +44 -0
- tools/bolt.diy/app/routes/api.git-info.ts +69 -0
- tools/bolt.diy/app/routes/api.git-proxy.$.ts +178 -0
- tools/bolt.diy/app/routes/api.github-branches.ts +166 -0
- tools/bolt.diy/app/routes/api.github-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.github-stats.ts +198 -0
- tools/bolt.diy/app/routes/api.github-template.ts +242 -0
- tools/bolt.diy/app/routes/api.github-user.ts +287 -0
- tools/bolt.diy/app/routes/api.gitlab-branches.ts +143 -0
- tools/bolt.diy/app/routes/api.gitlab-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.gitlab-projects.ts +105 -0
- tools/bolt.diy/app/routes/api.health.ts +8 -0
- tools/bolt.diy/app/routes/api.llmcall.ts +298 -0
- tools/bolt.diy/app/routes/api.mandate.ts +351 -0
- tools/bolt.diy/app/routes/api.mcp-check.ts +16 -0
- tools/bolt.diy/app/routes/api.mcp-update-config.ts +23 -0
- tools/bolt.diy/app/routes/api.models.$provider.ts +2 -0
- tools/bolt.diy/app/routes/api.models.ts +90 -0
- tools/bolt.diy/app/routes/api.netlify-deploy.ts +240 -0
- tools/bolt.diy/app/routes/api.netlify-user.ts +142 -0
- tools/bolt.diy/app/routes/api.supabase-user.ts +199 -0
- tools/bolt.diy/app/routes/api.supabase.query.ts +92 -0
- tools/bolt.diy/app/routes/api.supabase.ts +56 -0
- tools/bolt.diy/app/routes/api.supabase.variables.ts +32 -0
- tools/bolt.diy/app/routes/api.system.diagnostics.ts +142 -0
- tools/bolt.diy/app/routes/api.system.disk-info.ts +311 -0
- tools/bolt.diy/app/routes/api.system.git-info.ts +332 -0
- tools/bolt.diy/app/routes/api.update.ts +21 -0
- tools/bolt.diy/app/routes/api.vercel-deploy.ts +497 -0
- tools/bolt.diy/app/routes/api.vercel-user.ts +161 -0
- tools/bolt.diy/app/routes/api.workflow-status.$proposalId.ts +309 -0
- tools/bolt.diy/app/routes/chat.$id.tsx +8 -0
- tools/bolt.diy/app/routes/execute.$mandateId.tsx +432 -0
- tools/bolt.diy/app/routes/git.tsx +25 -0
- tools/bolt.diy/app/routes/observability.$mandateId.tsx +50 -0
- tools/bolt.diy/app/routes/webcontainer.connect.$id.tsx +32 -0
- tools/bolt.diy/app/routes/webcontainer.preview.$id.tsx +97 -0
- tools/bolt.diy/app/routes/workflow.$proposalId.tsx +170 -0
- tools/bolt.diy/app/styles/animations.scss +49 -0
- tools/bolt.diy/app/styles/components/code.scss +9 -0
- tools/bolt.diy/app/styles/components/editor.scss +135 -0
- tools/bolt.diy/app/styles/components/resize-handle.scss +30 -0
- tools/bolt.diy/app/styles/components/terminal.scss +3 -0
- tools/bolt.diy/app/styles/components/toast.scss +23 -0
- tools/bolt.diy/app/styles/diff-view.css +72 -0
- tools/bolt.diy/app/styles/index.scss +73 -0
- tools/bolt.diy/app/styles/variables.scss +255 -0
- tools/bolt.diy/app/styles/z-index.scss +37 -0
- tools/bolt.diy/app/types/GitHub.ts +182 -0
- tools/bolt.diy/app/types/GitLab.ts +103 -0
- tools/bolt.diy/app/types/actions.ts +85 -0
- tools/bolt.diy/app/types/artifact.ts +5 -0
- tools/bolt.diy/app/types/context.ts +26 -0
- tools/bolt.diy/app/types/design-scheme.ts +93 -0
- tools/bolt.diy/app/types/global.d.ts +13 -0
- tools/bolt.diy/app/types/mandate.ts +333 -0
- tools/bolt.diy/app/types/model.ts +25 -0
- tools/bolt.diy/app/types/netlify.ts +94 -0
- tools/bolt.diy/app/types/supabase.ts +54 -0
- tools/bolt.diy/app/types/template.ts +8 -0
- tools/bolt.diy/app/types/terminal.ts +9 -0
- tools/bolt.diy/app/types/theme.ts +1 -0
- tools/bolt.diy/app/types/vercel.ts +67 -0
- tools/bolt.diy/app/utils/buffer.ts +29 -0
- tools/bolt.diy/app/utils/classNames.ts +65 -0
- tools/bolt.diy/app/utils/constants.ts +147 -0
- tools/bolt.diy/app/utils/debounce.ts +13 -0
- tools/bolt.diy/app/utils/debugLogger.ts +1284 -0
- tools/bolt.diy/app/utils/diff.spec.ts +11 -0
- tools/bolt.diy/app/utils/diff.ts +117 -0
- tools/bolt.diy/app/utils/easings.ts +3 -0
- tools/bolt.diy/app/utils/fileLocks.ts +96 -0
- tools/bolt.diy/app/utils/fileUtils.ts +121 -0
- tools/bolt.diy/app/utils/folderImport.ts +73 -0
- tools/bolt.diy/app/utils/formatSize.ts +12 -0
- tools/bolt.diy/app/utils/getLanguageFromExtension.ts +24 -0
- tools/bolt.diy/app/utils/githubStats.ts +9 -0
- tools/bolt.diy/app/utils/gitlabStats.ts +54 -0
- tools/bolt.diy/app/utils/logger.ts +162 -0
- tools/bolt.diy/app/utils/markdown.ts +155 -0
- tools/bolt.diy/app/utils/mobile.ts +4 -0
- tools/bolt.diy/app/utils/os.ts +4 -0
- tools/bolt.diy/app/utils/path.ts +19 -0
- tools/bolt.diy/app/utils/projectCommands.ts +197 -0
- tools/bolt.diy/app/utils/promises.ts +19 -0
- tools/bolt.diy/app/utils/react.ts +6 -0
- tools/bolt.diy/app/utils/sampler.ts +49 -0
- tools/bolt.diy/app/utils/selectStarterTemplate.ts +255 -0
- tools/bolt.diy/app/utils/shell.ts +384 -0
- tools/bolt.diy/app/utils/stacktrace.ts +27 -0
- tools/bolt.diy/app/utils/stripIndent.ts +23 -0
- tools/bolt.diy/app/utils/terminal.ts +11 -0
- tools/bolt.diy/app/utils/unreachable.ts +3 -0
- tools/bolt.diy/app/vite-env.d.ts +2 -0
- tools/bolt.diy/assets/entitlements.mac.plist +25 -0
- tools/bolt.diy/assets/icons/icon.icns +0 -0
- tools/bolt.diy/assets/icons/icon.ico +0 -0
- tools/bolt.diy/assets/icons/icon.png +0 -0
- tools/bolt.diy/bindings.js +78 -0
- tools/bolt.diy/bindings.sh +33 -0
- tools/bolt.diy/docker-compose.yaml +145 -0
- tools/bolt.diy/electron/main/index.ts +201 -0
- tools/bolt.diy/electron/main/tsconfig.json +30 -0
- tools/bolt.diy/electron/main/ui/menu.ts +29 -0
- tools/bolt.diy/electron/main/ui/window.ts +54 -0
- tools/bolt.diy/electron/main/utils/auto-update.ts +110 -0
- tools/bolt.diy/electron/main/utils/constants.ts +4 -0
- tools/bolt.diy/electron/main/utils/cookie.ts +40 -0
- tools/bolt.diy/electron/main/utils/reload.ts +35 -0
- tools/bolt.diy/electron/main/utils/serve.ts +71 -0
- tools/bolt.diy/electron/main/utils/store.ts +3 -0
- tools/bolt.diy/electron/main/utils/vite-server.ts +44 -0
- tools/bolt.diy/electron/main/vite.config.ts +44 -0
- tools/bolt.diy/electron/preload/index.ts +22 -0
- tools/bolt.diy/electron/preload/tsconfig.json +7 -0
- tools/bolt.diy/electron/preload/vite.config.ts +31 -0
- tools/bolt.diy/electron-builder.yml +64 -0
- tools/bolt.diy/electron-update.yml +4 -0
- tools/bolt.diy/eslint.config.mjs +57 -0
- tools/bolt.diy/functions/[[path]].ts +12 -0
- tools/bolt.diy/icons/angular.svg +1 -0
- tools/bolt.diy/icons/astro.svg +8 -0
- tools/bolt.diy/icons/chat.svg +1 -0
- tools/bolt.diy/icons/expo-brand.svg +1 -0
- tools/bolt.diy/icons/expo.svg +4 -0
- tools/bolt.diy/icons/logo-text.svg +1 -0
- tools/bolt.diy/icons/logo.svg +4 -0
- tools/bolt.diy/icons/mcp.svg +1 -0
- tools/bolt.diy/icons/nativescript.svg +1 -0
- tools/bolt.diy/icons/netlify.svg +10 -0
- tools/bolt.diy/icons/nextjs.svg +1 -0
- tools/bolt.diy/icons/nuxt.svg +1 -0
- tools/bolt.diy/icons/qwik.svg +1 -0
- tools/bolt.diy/icons/react.svg +1 -0
- tools/bolt.diy/icons/remix.svg +24 -0
- tools/bolt.diy/icons/remotion.svg +1 -0
- tools/bolt.diy/icons/shadcn.svg +21 -0
- tools/bolt.diy/icons/slidev.svg +60 -0
- tools/bolt.diy/icons/solidjs.svg +1 -0
- tools/bolt.diy/icons/stars.svg +1 -0
- tools/bolt.diy/icons/svelte.svg +1 -0
- tools/bolt.diy/icons/typescript.svg +1 -0
- tools/bolt.diy/icons/vite.svg +1 -0
- tools/bolt.diy/icons/vue.svg +1 -0
- tools/bolt.diy/load-context.ts +9 -0
- tools/bolt.diy/notarize.cjs +31 -0
- tools/bolt.diy/package.json +218 -0
- tools/bolt.diy/playwright.config.preview.ts +35 -0
- tools/bolt.diy/pre-start.cjs +26 -0
- tools/bolt.diy/public/apple-touch-icon-precomposed.png +0 -0
- tools/bolt.diy/public/apple-touch-icon.png +0 -0
- tools/bolt.diy/public/favicon.ico +0 -0
- tools/bolt.diy/public/favicon.svg +4 -0
- tools/bolt.diy/public/icons/AmazonBedrock.svg +1 -0
- tools/bolt.diy/public/icons/Anthropic.svg +4 -0
- tools/bolt.diy/public/icons/Cohere.svg +4 -0
- tools/bolt.diy/public/icons/Deepseek.svg +5 -0
- tools/bolt.diy/public/icons/Default.svg +4 -0
- tools/bolt.diy/public/icons/Google.svg +4 -0
- tools/bolt.diy/public/icons/Groq.svg +4 -0
- tools/bolt.diy/public/icons/HuggingFace.svg +4 -0
- tools/bolt.diy/public/icons/Hyperbolic.svg +3 -0
- tools/bolt.diy/public/icons/LMStudio.svg +5 -0
- tools/bolt.diy/public/icons/Mistral.svg +4 -0
- tools/bolt.diy/public/icons/Ollama.svg +4 -0
- tools/bolt.diy/public/icons/OpenAI.svg +4 -0
- tools/bolt.diy/public/icons/OpenAILike.svg +4 -0
- tools/bolt.diy/public/icons/OpenRouter.svg +4 -0
- tools/bolt.diy/public/icons/Perplexity.svg +4 -0
- tools/bolt.diy/public/icons/Together.svg +4 -0
- tools/bolt.diy/public/icons/xAI.svg +5 -0
- tools/bolt.diy/public/inspector-script.js +292 -0
- tools/bolt.diy/public/logo-dark-styled.png +0 -0
- tools/bolt.diy/public/logo-dark.png +0 -0
- tools/bolt.diy/public/logo-light-styled.png +0 -0
- tools/bolt.diy/public/logo-light.png +0 -0
- tools/bolt.diy/public/logo.svg +15 -0
- tools/bolt.diy/public/social_preview_index.jpg +0 -0
- tools/bolt.diy/scripts/clean.js +45 -0
- tools/bolt.diy/scripts/electron-dev.mjs +181 -0
- tools/bolt.diy/scripts/setup-env.sh +41 -0
- tools/bolt.diy/scripts/update-imports.sh +7 -0
- tools/bolt.diy/scripts/update.sh +52 -0
- tools/bolt.diy/services/execution-governor/Dockerfile +41 -0
- tools/bolt.diy/services/execution-governor/config.ts +42 -0
- tools/bolt.diy/services/execution-governor/index.ts +683 -0
- tools/bolt.diy/services/execution-governor/metrics.ts +141 -0
- tools/bolt.diy/services/execution-governor/package.json +31 -0
- tools/bolt.diy/services/execution-governor/priority-queue.ts +139 -0
- tools/bolt.diy/services/execution-governor/tsconfig.json +21 -0
- tools/bolt.diy/services/execution-governor/types.ts +145 -0
- tools/bolt.diy/services/headless-executor/Dockerfile +43 -0
- tools/bolt.diy/services/headless-executor/executor.ts +210 -0
- tools/bolt.diy/services/headless-executor/index.ts +323 -0
- tools/bolt.diy/services/headless-executor/package.json +27 -0
- tools/bolt.diy/services/headless-executor/tsconfig.json +21 -0
- tools/bolt.diy/services/headless-executor/types.ts +38 -0
- tools/bolt.diy/test-workflows.sh +240 -0
- tools/bolt.diy/tests/integration/corporate-swarm.test.ts +208 -0
- tools/bolt.diy/tests/mandates/budget-limited.json +34 -0
- tools/bolt.diy/tests/mandates/complex.json +53 -0
- tools/bolt.diy/tests/mandates/constraint-enforced.json +36 -0
- tools/bolt.diy/tests/mandates/simple.json +35 -0
- tools/bolt.diy/tsconfig.json +37 -0
- tools/bolt.diy/types/istextorbinary.d.ts +15 -0
- tools/bolt.diy/uno.config.ts +279 -0
- tools/bolt.diy/vite-electron.config.ts +76 -0
- tools/bolt.diy/vite.config.ts +112 -0
- tools/bolt.diy/worker-configuration.d.ts +22 -0
- tools/bolt.diy/wrangler.toml +6 -0
- tools/code_generator.py +461 -0
- tools/file_operations.py +465 -0
- tools/mandate_generator.py +337 -0
- tools/mcpClientUtils.py +1216 -0
- tools/sensors.py +285 -0
- utils/Agent_types.py +15 -0
- utils/AnyToStr.py +0 -0
- utils/HHCS.py +277 -0
- utils/__init__.py +30 -0
- utils/agent.py +3627 -0
- utils/aop.py +2948 -0
- utils/canonical.py +143 -0
- utils/conversation.py +1195 -0
- utils/doctrine_versioning +230 -0
- utils/formatter.py +474 -0
- utils/ledger.py +311 -0
- utils/out_types.py +16 -0
- utils/rollback.py +339 -0
- utils/router.py +929 -0
- utils/tui.py +1908 -0
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CRCA-SD Core: State, Controls, Dynamics, Constraints, and Forward Simulation
|
|
3
|
+
|
|
4
|
+
This module implements the fundamental components for socioeconomic dynamics simulation:
|
|
5
|
+
- State vector with 15 core variables
|
|
6
|
+
- Control vector with budget shares and allocations
|
|
7
|
+
- Dynamics model with macro system dynamics equations
|
|
8
|
+
- Constraint checker for hard feasibility constraints
|
|
9
|
+
- Forward simulator for multi-step trajectory simulation
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import Dict, List, Optional, Tuple, Any
|
|
13
|
+
import numpy as np
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from loguru import logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class StateVector:
|
|
20
|
+
"""
|
|
21
|
+
State vector representing the socioeconomic system state.
|
|
22
|
+
|
|
23
|
+
Contains 15 core variables:
|
|
24
|
+
- Macro: P (population), L (labor), U (unemployment), W (wage), S (stability)
|
|
25
|
+
- Human capital: ℓ (literacy), Ecap (education capacity), Hcap (healthcare capacity)
|
|
26
|
+
- Capital: K (capital stock), I (infrastructure health), Tcap (transport capacity)
|
|
27
|
+
- Stocks: E_stock (energy), F_stock (food), M_stock (materials), C (ecological damage)
|
|
28
|
+
- Output: Y (GDP proxy)
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
P: Population
|
|
32
|
+
L: Labor force
|
|
33
|
+
U: Unemployment rate [0, 1]
|
|
34
|
+
W: Average wage proxy
|
|
35
|
+
S: Social stability proxy [0, 1]
|
|
36
|
+
literacy: Literacy rate [0, 1]
|
|
37
|
+
Ecap: Education capacity (seats/teachers)
|
|
38
|
+
Hcap: Healthcare capacity (beds/staff)
|
|
39
|
+
K: Productive capital stock
|
|
40
|
+
I: Infrastructure health index [0, 1]
|
|
41
|
+
Tcap: Transport capacity (ton-km/day)
|
|
42
|
+
E_stock: Stored energy (or fuel reserve proxy)
|
|
43
|
+
F_stock: Food stock
|
|
44
|
+
M_stock: Critical materials stock
|
|
45
|
+
C: Ecological damage / carbon stock (irreversible)
|
|
46
|
+
Y: GDP proxy (or output index)
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# Macro variables
|
|
50
|
+
P: float = 1000000.0 # Population
|
|
51
|
+
L: float = 500000.0 # Labor force
|
|
52
|
+
U: float = 0.05 # Unemployment rate [0, 1]
|
|
53
|
+
W: float = 1.0 # Average wage proxy
|
|
54
|
+
S: float = 0.8 # Social stability proxy [0, 1]
|
|
55
|
+
|
|
56
|
+
# Human capital
|
|
57
|
+
literacy: float = 0.7 # Literacy rate [0, 1]
|
|
58
|
+
Ecap: float = 10000.0 # Education capacity
|
|
59
|
+
Hcap: float = 5000.0 # Healthcare capacity
|
|
60
|
+
|
|
61
|
+
# Capital & infrastructure
|
|
62
|
+
K: float = 1000000.0 # Productive capital stock
|
|
63
|
+
I: float = 0.8 # Infrastructure health index [0, 1]
|
|
64
|
+
Tcap: float = 10000.0 # Transport capacity (ton-km/day)
|
|
65
|
+
|
|
66
|
+
# Stocks
|
|
67
|
+
E_stock: float = 50000.0 # Stored energy
|
|
68
|
+
F_stock: float = 30000.0 # Food stock
|
|
69
|
+
M_stock: float = 20000.0 # Critical materials stock
|
|
70
|
+
C: float = 0.0 # Ecological damage (irreversible)
|
|
71
|
+
|
|
72
|
+
# Output
|
|
73
|
+
Y: float = 1000000.0 # GDP proxy
|
|
74
|
+
|
|
75
|
+
def to_dict(self) -> Dict[str, float]:
|
|
76
|
+
"""
|
|
77
|
+
Convert state vector to dictionary.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Dict[str, float]: Dictionary mapping variable names to values
|
|
81
|
+
"""
|
|
82
|
+
return {
|
|
83
|
+
"P": self.P,
|
|
84
|
+
"L": self.L,
|
|
85
|
+
"U": self.U,
|
|
86
|
+
"W": self.W,
|
|
87
|
+
"S": self.S,
|
|
88
|
+
"literacy": self.literacy,
|
|
89
|
+
"Ecap": self.Ecap,
|
|
90
|
+
"Hcap": self.Hcap,
|
|
91
|
+
"K": self.K,
|
|
92
|
+
"I": self.I,
|
|
93
|
+
"Tcap": self.Tcap,
|
|
94
|
+
"E_stock": self.E_stock,
|
|
95
|
+
"F_stock": self.F_stock,
|
|
96
|
+
"M_stock": self.M_stock,
|
|
97
|
+
"C": self.C,
|
|
98
|
+
"Y": self.Y,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def from_dict(cls, state_dict: Dict[str, float]) -> "StateVector":
|
|
103
|
+
"""
|
|
104
|
+
Create state vector from dictionary.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
state_dict: Dictionary mapping variable names to values
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
StateVector: New state vector instance
|
|
111
|
+
"""
|
|
112
|
+
return cls(**state_dict)
|
|
113
|
+
|
|
114
|
+
def validate(self) -> Tuple[bool, List[str]]:
|
|
115
|
+
"""
|
|
116
|
+
Validate state vector bounds and constraints.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Tuple[bool, List[str]]: (is_valid, list of violations)
|
|
120
|
+
"""
|
|
121
|
+
violations = []
|
|
122
|
+
|
|
123
|
+
# Check non-negativity
|
|
124
|
+
if self.P < 0:
|
|
125
|
+
violations.append("Population P must be non-negative")
|
|
126
|
+
if self.L < 0:
|
|
127
|
+
violations.append("Labor force L must be non-negative")
|
|
128
|
+
if self.K < 0:
|
|
129
|
+
violations.append("Capital stock K must be non-negative")
|
|
130
|
+
if self.E_stock < 0:
|
|
131
|
+
violations.append("Energy stock must be non-negative")
|
|
132
|
+
if self.F_stock < 0:
|
|
133
|
+
violations.append("Food stock must be non-negative")
|
|
134
|
+
if self.M_stock < 0:
|
|
135
|
+
violations.append("Materials stock must be non-negative")
|
|
136
|
+
if self.C < 0:
|
|
137
|
+
violations.append("Ecological damage C must be non-negative")
|
|
138
|
+
|
|
139
|
+
# Check bounds [0, 1]
|
|
140
|
+
if not (0 <= self.U <= 1):
|
|
141
|
+
violations.append("Unemployment U must be in [0, 1]")
|
|
142
|
+
if not (0 <= self.S <= 1):
|
|
143
|
+
violations.append("Social stability S must be in [0, 1]")
|
|
144
|
+
if not (0 <= self.literacy <= 1):
|
|
145
|
+
violations.append("Literacy rate must be in [0, 1]")
|
|
146
|
+
if not (0 <= self.I <= 1):
|
|
147
|
+
violations.append("Infrastructure health I must be in [0, 1]")
|
|
148
|
+
|
|
149
|
+
# Check logical constraints
|
|
150
|
+
if self.L > self.P:
|
|
151
|
+
violations.append("Labor force L cannot exceed population P")
|
|
152
|
+
|
|
153
|
+
is_valid = len(violations) == 0
|
|
154
|
+
return is_valid, violations
|
|
155
|
+
|
|
156
|
+
def copy(self) -> "StateVector":
|
|
157
|
+
"""
|
|
158
|
+
Create a deep copy of the state vector.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
StateVector: New state vector with copied values
|
|
162
|
+
"""
|
|
163
|
+
return StateVector(
|
|
164
|
+
P=self.P,
|
|
165
|
+
L=self.L,
|
|
166
|
+
U=self.U,
|
|
167
|
+
W=self.W,
|
|
168
|
+
S=self.S,
|
|
169
|
+
literacy=self.literacy,
|
|
170
|
+
Ecap=self.Ecap,
|
|
171
|
+
Hcap=self.Hcap,
|
|
172
|
+
K=self.K,
|
|
173
|
+
I=self.I,
|
|
174
|
+
Tcap=self.Tcap,
|
|
175
|
+
E_stock=self.E_stock,
|
|
176
|
+
F_stock=self.F_stock,
|
|
177
|
+
M_stock=self.M_stock,
|
|
178
|
+
C=self.C,
|
|
179
|
+
Y=self.Y,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def snapshot(self) -> Dict[str, Any]:
|
|
183
|
+
"""
|
|
184
|
+
Create a snapshot of the state for rollback/recovery.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Dict[str, Any]: Snapshot dictionary with timestamp and state
|
|
188
|
+
"""
|
|
189
|
+
import time
|
|
190
|
+
return {
|
|
191
|
+
"timestamp": time.time(),
|
|
192
|
+
"state": self.to_dict(),
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@classmethod
|
|
196
|
+
def restore_from_snapshot(cls, snapshot: Dict[str, Any]) -> "StateVector":
|
|
197
|
+
"""
|
|
198
|
+
Restore state vector from snapshot.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
snapshot: Snapshot dictionary from snapshot() method
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
StateVector: Restored state vector
|
|
205
|
+
"""
|
|
206
|
+
state_dict = snapshot.get("state", snapshot) # Handle both formats
|
|
207
|
+
return cls.from_dict(state_dict)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@dataclass
|
|
211
|
+
class ControlVector:
|
|
212
|
+
"""
|
|
213
|
+
Control vector representing policy decisions.
|
|
214
|
+
|
|
215
|
+
Contains:
|
|
216
|
+
- Budget shares b_t on simplex (sums to 1, all >= 0)
|
|
217
|
+
- Allocation decisions a_t for scarce resources
|
|
218
|
+
- Logistics flow plan f_t (placeholder for Phase A)
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
budget_shares: Dictionary mapping budget categories to shares (must sum to 1)
|
|
222
|
+
allocations: Dictionary mapping resource types to allocation amounts
|
|
223
|
+
flows: Dictionary mapping flow identifiers to flow amounts (placeholder)
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
budget_shares: Dict[str, float] = field(default_factory=dict)
|
|
227
|
+
allocations: Dict[str, float] = field(default_factory=dict)
|
|
228
|
+
flows: Dict[str, float] = field(default_factory=dict)
|
|
229
|
+
|
|
230
|
+
def validate_simplex(self) -> Tuple[bool, Optional[str]]:
|
|
231
|
+
"""
|
|
232
|
+
Validate that budget shares form a simplex (sum to 1, all >= 0).
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Tuple[bool, Optional[str]]: (is_valid, error_message)
|
|
236
|
+
"""
|
|
237
|
+
if not self.budget_shares:
|
|
238
|
+
return False, "Budget shares dictionary is empty"
|
|
239
|
+
|
|
240
|
+
total = sum(self.budget_shares.values())
|
|
241
|
+
tolerance = 1e-6
|
|
242
|
+
|
|
243
|
+
if abs(total - 1.0) > tolerance:
|
|
244
|
+
return False, f"Budget shares sum to {total}, must sum to 1.0"
|
|
245
|
+
|
|
246
|
+
for category, share in self.budget_shares.items():
|
|
247
|
+
if share < 0:
|
|
248
|
+
return False, f"Budget share for {category} is negative: {share}"
|
|
249
|
+
|
|
250
|
+
return True, None
|
|
251
|
+
|
|
252
|
+
@classmethod
|
|
253
|
+
def sample_budget_simplex(
|
|
254
|
+
cls,
|
|
255
|
+
categories: List[str],
|
|
256
|
+
alpha: Optional[float] = None,
|
|
257
|
+
rng: Optional[np.random.Generator] = None
|
|
258
|
+
) -> "ControlVector":
|
|
259
|
+
"""
|
|
260
|
+
Sample budget shares from Dirichlet distribution (simplex).
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
categories: List of budget category names
|
|
264
|
+
alpha: Dirichlet concentration parameter (default: 1.0 for uniform)
|
|
265
|
+
rng: Random number generator (default: new generator)
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
ControlVector: New control vector with sampled budget shares
|
|
269
|
+
"""
|
|
270
|
+
if rng is None:
|
|
271
|
+
rng = np.random.default_rng()
|
|
272
|
+
|
|
273
|
+
if alpha is None:
|
|
274
|
+
alpha = 1.0
|
|
275
|
+
|
|
276
|
+
n = len(categories)
|
|
277
|
+
dirichlet_params = np.full(n, alpha)
|
|
278
|
+
sampled = rng.dirichlet(dirichlet_params)
|
|
279
|
+
|
|
280
|
+
budget_shares = {cat: float(val) for cat, val in zip(categories, sampled)}
|
|
281
|
+
|
|
282
|
+
return cls(budget_shares=budget_shares)
|
|
283
|
+
|
|
284
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
285
|
+
"""
|
|
286
|
+
Convert control vector to dictionary.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Dict[str, Any]: Dictionary representation
|
|
290
|
+
"""
|
|
291
|
+
return {
|
|
292
|
+
"budget_shares": self.budget_shares.copy(),
|
|
293
|
+
"allocations": self.allocations.copy(),
|
|
294
|
+
"flows": self.flows.copy(),
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
@classmethod
|
|
298
|
+
def from_dict(cls, control_dict: Dict[str, Any]) -> "ControlVector":
|
|
299
|
+
"""
|
|
300
|
+
Create control vector from dictionary.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
control_dict: Dictionary representation
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
ControlVector: New control vector instance
|
|
307
|
+
"""
|
|
308
|
+
return cls(
|
|
309
|
+
budget_shares=control_dict.get("budget_shares", {}).copy(),
|
|
310
|
+
allocations=control_dict.get("allocations", {}).copy(),
|
|
311
|
+
flows=control_dict.get("flows", {}).copy(),
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class DynamicsModel:
|
|
316
|
+
"""
|
|
317
|
+
Macro system dynamics model.
|
|
318
|
+
|
|
319
|
+
Implements discrete-time dynamics for socioeconomic system:
|
|
320
|
+
- Population growth with births, deaths, migration
|
|
321
|
+
- Labor force adjustment
|
|
322
|
+
- Unemployment with stable lag model
|
|
323
|
+
- Capital accumulation
|
|
324
|
+
- Infrastructure health evolution
|
|
325
|
+
- Literacy diffusion
|
|
326
|
+
- Output production (Cobb-Douglas with gating)
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
delta_K: Capital depreciation rate (default: 0.05)
|
|
330
|
+
delta_I: Infrastructure decay rate (default: 0.02)
|
|
331
|
+
alpha: Capital share in production (default: 0.3)
|
|
332
|
+
kappa_K: Capital investment efficiency (default: 0.8)
|
|
333
|
+
kappa_I: Infrastructure maintenance efficiency (default: 0.7)
|
|
334
|
+
kappa_literacy: Literacy diffusion rate (default: 0.1)
|
|
335
|
+
delta_literacy: Literacy disruption rate (default: 0.01)
|
|
336
|
+
alpha_U: Unemployment adjustment rate (default: 0.1)
|
|
337
|
+
alpha_rho: Labor force participation adjustment (default: 0.05)
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
def __init__(
|
|
341
|
+
self,
|
|
342
|
+
delta_K: float = 0.05,
|
|
343
|
+
delta_I: float = 0.02,
|
|
344
|
+
alpha: float = 0.3,
|
|
345
|
+
kappa_K: float = 0.8,
|
|
346
|
+
kappa_I: float = 0.7,
|
|
347
|
+
kappa_literacy: float = 0.1,
|
|
348
|
+
delta_literacy: float = 0.01,
|
|
349
|
+
alpha_U: float = 0.1,
|
|
350
|
+
alpha_rho: float = 0.05,
|
|
351
|
+
) -> None:
|
|
352
|
+
"""Initialize dynamics model with parameters."""
|
|
353
|
+
self.delta_K = delta_K
|
|
354
|
+
self.delta_I = delta_I
|
|
355
|
+
self.alpha = alpha
|
|
356
|
+
self.kappa_K = kappa_K
|
|
357
|
+
self.kappa_I = kappa_I
|
|
358
|
+
self.kappa_literacy = kappa_literacy
|
|
359
|
+
self.delta_literacy = delta_literacy
|
|
360
|
+
self.alpha_U = alpha_U
|
|
361
|
+
self.alpha_rho = alpha_rho
|
|
362
|
+
|
|
363
|
+
def step(
|
|
364
|
+
self,
|
|
365
|
+
x_t: StateVector,
|
|
366
|
+
u_t: ControlVector,
|
|
367
|
+
w_t: Optional[Dict[str, float]] = None
|
|
368
|
+
) -> StateVector:
|
|
369
|
+
"""
|
|
370
|
+
Single time step evolution: x_{t+1} = f(x_t, u_t, w_t).
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
x_t: Current state vector
|
|
374
|
+
u_t: Control vector
|
|
375
|
+
w_t: Disturbance vector (optional)
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
StateVector: Next state vector x_{t+1}
|
|
379
|
+
"""
|
|
380
|
+
if w_t is None:
|
|
381
|
+
w_t = {}
|
|
382
|
+
|
|
383
|
+
# Validate control
|
|
384
|
+
is_valid, error = u_t.validate_simplex()
|
|
385
|
+
if not is_valid:
|
|
386
|
+
logger.warning(f"Invalid control vector: {error}")
|
|
387
|
+
|
|
388
|
+
# Extract budget shares
|
|
389
|
+
b_E = u_t.budget_shares.get("energy", 0.0)
|
|
390
|
+
b_F = u_t.budget_shares.get("food", 0.0)
|
|
391
|
+
b_I = u_t.budget_shares.get("infrastructure", 0.0)
|
|
392
|
+
b_edu = u_t.budget_shares.get("education", 0.0)
|
|
393
|
+
b_health = u_t.budget_shares.get("healthcare", 0.0)
|
|
394
|
+
b_RD = u_t.budget_shares.get("R&D", 0.0)
|
|
395
|
+
b_welfare = u_t.budget_shares.get("welfare", 0.0)
|
|
396
|
+
|
|
397
|
+
# Total budget (derived from output)
|
|
398
|
+
B_t = x_t.Y * 0.2 # 20% of output as budget
|
|
399
|
+
|
|
400
|
+
# Disturbances
|
|
401
|
+
demand_shock = w_t.get("demand_shock", 0.0)
|
|
402
|
+
trade_shock = w_t.get("trade_shock", 0.0)
|
|
403
|
+
productivity_shock = w_t.get("productivity_shock", 1.0)
|
|
404
|
+
disaster_shock = w_t.get("disaster_shock", 0.0)
|
|
405
|
+
|
|
406
|
+
# Population dynamics (simplified: constant for now)
|
|
407
|
+
births = x_t.P * 0.02 # 2% birth rate
|
|
408
|
+
deaths = x_t.P * 0.015 # 1.5% death rate (adjusted by healthcare)
|
|
409
|
+
death_reduction = b_health * B_t * 0.0001
|
|
410
|
+
deaths = max(0, deaths - death_reduction)
|
|
411
|
+
migration = (x_t.S - 0.5) * x_t.P * 0.001 # Migration based on stability
|
|
412
|
+
P_next = x_t.P + births - deaths + migration
|
|
413
|
+
|
|
414
|
+
# Labor force participation
|
|
415
|
+
rho_t = x_t.L / x_t.P if x_t.P > 0 else 0.5
|
|
416
|
+
rho_next = rho_t + self.alpha_rho * (x_t.literacy - rho_t) + w_t.get("labor_shock", 0.0)
|
|
417
|
+
rho_next = np.clip(rho_next, 0.3, 0.8) # Reasonable bounds
|
|
418
|
+
L_next = rho_next * P_next
|
|
419
|
+
|
|
420
|
+
# Unemployment dynamics (stable lag model)
|
|
421
|
+
# Target unemployment depends on output, investment, and shocks
|
|
422
|
+
U_target = 0.05 + 0.1 * (1.0 - min(1.0, x_t.Y / 1000000.0)) # Higher if output low
|
|
423
|
+
U_target += demand_shock * 0.1
|
|
424
|
+
U_target = np.clip(U_target, 0.0, 0.3)
|
|
425
|
+
|
|
426
|
+
U_next = x_t.U + self.alpha_U * (U_target - x_t.U) + w_t.get("unemployment_shock", 0.0)
|
|
427
|
+
U_next = np.clip(U_next, 0.0, 1.0)
|
|
428
|
+
|
|
429
|
+
# Capital accumulation
|
|
430
|
+
I_inv = self.kappa_K * b_I * B_t * self._phi_infrastructure(x_t.I)
|
|
431
|
+
K_next = (1 - self.delta_K) * x_t.K + I_inv
|
|
432
|
+
|
|
433
|
+
# Infrastructure health
|
|
434
|
+
maintenance = self.kappa_I * b_I * B_t * 0.0001
|
|
435
|
+
usage_decay = self.delta_I * x_t.I * (1.0 + abs(demand_shock))
|
|
436
|
+
I_next = np.clip(x_t.I + maintenance - usage_decay, 0.0, 1.0)
|
|
437
|
+
|
|
438
|
+
# Transport capacity (depends on infrastructure)
|
|
439
|
+
Tcap_next = x_t.Tcap * (0.9 + 0.1 * I_next) # Degrades if infrastructure poor
|
|
440
|
+
|
|
441
|
+
# Literacy diffusion
|
|
442
|
+
education_investment = min(x_t.Ecap, b_edu * B_t)
|
|
443
|
+
literacy_gain = self.kappa_literacy * education_investment * (1.0 - x_t.literacy) / 10000.0
|
|
444
|
+
literacy_loss = self.delta_literacy * disaster_shock
|
|
445
|
+
literacy_next = np.clip(x_t.literacy + literacy_gain - literacy_loss, 0.0, 1.0)
|
|
446
|
+
|
|
447
|
+
# Education and healthcare capacity (slow adjustment)
|
|
448
|
+
Ecap_next = x_t.Ecap + b_edu * B_t * 0.01 - x_t.Ecap * 0.02
|
|
449
|
+
Ecap_next = max(0, Ecap_next)
|
|
450
|
+
|
|
451
|
+
Hcap_next = x_t.Hcap + b_health * B_t * 0.01 - x_t.Hcap * 0.02
|
|
452
|
+
Hcap_next = max(0, Hcap_next)
|
|
453
|
+
|
|
454
|
+
# Stock dynamics (simplified)
|
|
455
|
+
# Energy stock
|
|
456
|
+
E_gen = b_E * B_t * 0.1 # Energy generation from budget
|
|
457
|
+
E_demand = x_t.Y * 0.0001 + x_t.Tcap * 0.01 # Energy demand
|
|
458
|
+
E_import = w_t.get("energy_import", 0.0) * (1.0 - trade_shock)
|
|
459
|
+
E_next = x_t.E_stock + E_gen + E_import - E_demand
|
|
460
|
+
E_next = max(0, E_next)
|
|
461
|
+
|
|
462
|
+
# Food stock
|
|
463
|
+
F_prod = b_F * B_t * 0.2 # Food production
|
|
464
|
+
F_demand = x_t.P * 0.03 # Per capita food demand
|
|
465
|
+
F_import = w_t.get("food_import", 0.0) * (1.0 - trade_shock)
|
|
466
|
+
F_next = x_t.F_stock + F_prod + F_import - F_demand
|
|
467
|
+
F_next = max(0, F_next)
|
|
468
|
+
|
|
469
|
+
# Materials stock
|
|
470
|
+
M_prod = b_RD * B_t * 0.1
|
|
471
|
+
M_demand = I_inv * 0.1
|
|
472
|
+
M_next = x_t.M_stock + M_prod - M_demand
|
|
473
|
+
M_next = max(0, M_next)
|
|
474
|
+
|
|
475
|
+
# Ecological damage (irreversible, accumulates)
|
|
476
|
+
emissions = E_demand * 0.001 # Emissions from energy use
|
|
477
|
+
C_next = x_t.C + emissions # Irreversible accumulation
|
|
478
|
+
|
|
479
|
+
# Output (Cobb-Douglas with energy/logistics gating)
|
|
480
|
+
A_t = productivity_shock # Total factor productivity
|
|
481
|
+
L_employed = L_next * (1 - U_next)
|
|
482
|
+
g_E = self._gate_energy(x_t.E_stock, E_demand)
|
|
483
|
+
h_T = self._gate_transport(x_t.Tcap)
|
|
484
|
+
|
|
485
|
+
Y_next = A_t * (K_next ** self.alpha) * (L_employed ** (1 - self.alpha)) * g_E * h_T
|
|
486
|
+
|
|
487
|
+
# Wage (simplified: depends on output per worker)
|
|
488
|
+
W_next = x_t.W * (1.0 + 0.1 * (Y_next / max(1, L_employed) - x_t.W) / x_t.W)
|
|
489
|
+
W_next = max(0.1, W_next)
|
|
490
|
+
|
|
491
|
+
# Social stability (depends on unemployment, welfare, literacy)
|
|
492
|
+
stability_gain = b_welfare * B_t * 0.0001 + literacy_next * 0.1
|
|
493
|
+
stability_loss = U_next * 0.2 + (1.0 - min(1.0, F_next / (x_t.P * 0.03))) * 0.3
|
|
494
|
+
S_next = np.clip(x_t.S + stability_gain - stability_loss, 0.0, 1.0)
|
|
495
|
+
|
|
496
|
+
# Create next state
|
|
497
|
+
x_next = StateVector(
|
|
498
|
+
P=P_next,
|
|
499
|
+
L=L_next,
|
|
500
|
+
U=U_next,
|
|
501
|
+
W=W_next,
|
|
502
|
+
S=S_next,
|
|
503
|
+
literacy=literacy_next,
|
|
504
|
+
Ecap=Ecap_next,
|
|
505
|
+
Hcap=Hcap_next,
|
|
506
|
+
K=K_next,
|
|
507
|
+
I=I_next,
|
|
508
|
+
Tcap=Tcap_next,
|
|
509
|
+
E_stock=E_next,
|
|
510
|
+
F_stock=F_next,
|
|
511
|
+
M_stock=M_next,
|
|
512
|
+
C=C_next,
|
|
513
|
+
Y=Y_next,
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
return x_next
|
|
517
|
+
|
|
518
|
+
def _phi_infrastructure(self, I: float) -> float:
|
|
519
|
+
"""
|
|
520
|
+
Infrastructure gating function for investment efficiency.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
I: Infrastructure health [0, 1]
|
|
524
|
+
|
|
525
|
+
Returns:
|
|
526
|
+
float: Efficiency multiplier [0, 1]
|
|
527
|
+
"""
|
|
528
|
+
return 0.5 + 0.5 * I # Better infrastructure = better investment efficiency
|
|
529
|
+
|
|
530
|
+
def _gate_energy(self, E_stock: float, E_demand: float) -> float:
|
|
531
|
+
"""
|
|
532
|
+
Energy gating function for output.
|
|
533
|
+
|
|
534
|
+
Args:
|
|
535
|
+
E_stock: Available energy stock
|
|
536
|
+
E_demand: Energy demand
|
|
537
|
+
|
|
538
|
+
Returns:
|
|
539
|
+
float: Gating factor [0, 1]
|
|
540
|
+
"""
|
|
541
|
+
if E_demand <= 0:
|
|
542
|
+
return 1.0
|
|
543
|
+
ratio = E_stock / E_demand
|
|
544
|
+
return min(1.0, max(0.0, ratio)) # Linear gating
|
|
545
|
+
|
|
546
|
+
def _gate_transport(self, Tcap: float) -> float:
|
|
547
|
+
"""
|
|
548
|
+
Transport capacity gating function for output.
|
|
549
|
+
|
|
550
|
+
Args:
|
|
551
|
+
Tcap: Transport capacity
|
|
552
|
+
|
|
553
|
+
Returns:
|
|
554
|
+
float: Gating factor [0, 1]
|
|
555
|
+
"""
|
|
556
|
+
# Normalize: full capacity at 10000
|
|
557
|
+
normalized = min(1.0, Tcap / 10000.0)
|
|
558
|
+
return 0.5 + 0.5 * normalized # Minimum 50% even with no transport
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
class ConstraintChecker:
|
|
562
|
+
"""
|
|
563
|
+
Hard feasibility constraint checker.
|
|
564
|
+
|
|
565
|
+
Checks:
|
|
566
|
+
- Simplex budgets: sum(b_i) == 1, b_i >= 0
|
|
567
|
+
- Minimum needs: F_stock + F_in - F_out >= P * c_min
|
|
568
|
+
- Energy balance: E_gen + E_import + E_stock >= E_demand + E_logistics
|
|
569
|
+
- Capacity: flow(e) <= cap(e, Tcap_t, I_t)
|
|
570
|
+
- Welfare bounds: U_t <= U_max, S_t >= S_min
|
|
571
|
+
- Irreversibility: C_{t+1} >= C_t
|
|
572
|
+
|
|
573
|
+
Args:
|
|
574
|
+
U_max: Maximum allowed unemployment (default: 0.2)
|
|
575
|
+
S_min: Minimum required social stability (default: 0.3)
|
|
576
|
+
c_min: Minimum per-capita food consumption (default: 0.02)
|
|
577
|
+
"""
|
|
578
|
+
|
|
579
|
+
def __init__(
|
|
580
|
+
self,
|
|
581
|
+
U_max: float = 0.2,
|
|
582
|
+
S_min: float = 0.3,
|
|
583
|
+
c_min: float = 0.02,
|
|
584
|
+
) -> None:
|
|
585
|
+
"""Initialize constraint checker with bounds."""
|
|
586
|
+
self.U_max = U_max
|
|
587
|
+
self.S_min = S_min
|
|
588
|
+
self.c_min = c_min
|
|
589
|
+
|
|
590
|
+
def check_feasible(
|
|
591
|
+
self,
|
|
592
|
+
x_t: StateVector,
|
|
593
|
+
u_t: ControlVector
|
|
594
|
+
) -> Tuple[bool, List[str]]:
|
|
595
|
+
"""
|
|
596
|
+
Check if state and control satisfy all hard constraints.
|
|
597
|
+
|
|
598
|
+
Args:
|
|
599
|
+
x_t: State vector
|
|
600
|
+
u_t: Control vector
|
|
601
|
+
|
|
602
|
+
Returns:
|
|
603
|
+
Tuple[bool, List[str]]: (is_feasible, list of violations)
|
|
604
|
+
"""
|
|
605
|
+
violations = []
|
|
606
|
+
|
|
607
|
+
# Check simplex constraint
|
|
608
|
+
is_valid, error = u_t.validate_simplex()
|
|
609
|
+
if not is_valid:
|
|
610
|
+
violations.append(f"Budget simplex violation: {error}")
|
|
611
|
+
|
|
612
|
+
# Check minimum food needs
|
|
613
|
+
min_food = x_t.P * self.c_min
|
|
614
|
+
if x_t.F_stock < min_food:
|
|
615
|
+
violations.append(
|
|
616
|
+
f"Food stock {x_t.F_stock:.2f} below minimum {min_food:.2f} "
|
|
617
|
+
f"(P={x_t.P:.0f} * c_min={self.c_min})"
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
# Check energy balance (simplified: stock must cover demand)
|
|
621
|
+
E_demand = x_t.Y * 0.0001 + x_t.Tcap * 0.01
|
|
622
|
+
if x_t.E_stock < E_demand * 0.5: # At least 50% coverage
|
|
623
|
+
violations.append(
|
|
624
|
+
f"Energy stock {x_t.E_stock:.2f} insufficient for demand {E_demand:.2f}"
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
# Check welfare bounds
|
|
628
|
+
if x_t.U > self.U_max:
|
|
629
|
+
violations.append(
|
|
630
|
+
f"Unemployment {x_t.U:.3f} exceeds maximum {self.U_max}"
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
if x_t.S < self.S_min:
|
|
634
|
+
violations.append(
|
|
635
|
+
f"Social stability {x_t.S:.3f} below minimum {self.S_min}"
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
# Check state bounds (from StateVector.validate)
|
|
639
|
+
is_state_valid, state_violations = x_t.validate()
|
|
640
|
+
if not is_state_valid:
|
|
641
|
+
violations.extend(state_violations)
|
|
642
|
+
|
|
643
|
+
is_feasible = len(violations) == 0
|
|
644
|
+
return is_feasible, violations
|
|
645
|
+
|
|
646
|
+
def get_violations(
|
|
647
|
+
self,
|
|
648
|
+
x_t: StateVector,
|
|
649
|
+
u_t: ControlVector
|
|
650
|
+
) -> List[str]:
|
|
651
|
+
"""
|
|
652
|
+
Get detailed list of constraint violations.
|
|
653
|
+
|
|
654
|
+
Args:
|
|
655
|
+
x_t: State vector
|
|
656
|
+
u_t: Control vector
|
|
657
|
+
|
|
658
|
+
Returns:
|
|
659
|
+
List[str]: List of violation messages
|
|
660
|
+
"""
|
|
661
|
+
_, violations = self.check_feasible(x_t, u_t)
|
|
662
|
+
return violations
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
class ForwardSimulator:
|
|
666
|
+
"""
|
|
667
|
+
Forward simulator for multi-step trajectory simulation.
|
|
668
|
+
|
|
669
|
+
Simulates system evolution over multiple time steps with feasibility checking.
|
|
670
|
+
|
|
671
|
+
Args:
|
|
672
|
+
dynamics: Dynamics model
|
|
673
|
+
constraint_checker: Constraint checker
|
|
674
|
+
"""
|
|
675
|
+
|
|
676
|
+
def __init__(
|
|
677
|
+
self,
|
|
678
|
+
dynamics: DynamicsModel,
|
|
679
|
+
constraint_checker: ConstraintChecker
|
|
680
|
+
) -> None:
|
|
681
|
+
"""Initialize forward simulator."""
|
|
682
|
+
self.dynamics = dynamics
|
|
683
|
+
self.constraint_checker = constraint_checker
|
|
684
|
+
|
|
685
|
+
def simulate_scenario(
|
|
686
|
+
self,
|
|
687
|
+
x_0: StateVector,
|
|
688
|
+
policy: ControlVector,
|
|
689
|
+
disturbances: Optional[List[Dict[str, float]]] = None,
|
|
690
|
+
horizon: int = 10
|
|
691
|
+
) -> Tuple[List[StateVector], List[bool], Optional[int]]:
|
|
692
|
+
"""
|
|
693
|
+
Simulate forward trajectory under a policy.
|
|
694
|
+
|
|
695
|
+
Args:
|
|
696
|
+
x_0: Initial state
|
|
697
|
+
policy: Control policy (can be constant or time-varying)
|
|
698
|
+
disturbances: List of disturbance vectors (one per time step)
|
|
699
|
+
horizon: Simulation horizon (number of steps)
|
|
700
|
+
|
|
701
|
+
Returns:
|
|
702
|
+
Tuple[List[StateVector], List[bool], Optional[int]]:
|
|
703
|
+
(trajectory, feasibility_flags, first_violation_time)
|
|
704
|
+
"""
|
|
705
|
+
if disturbances is None:
|
|
706
|
+
disturbances = [{}] * horizon
|
|
707
|
+
|
|
708
|
+
trajectory = [x_0.copy()]
|
|
709
|
+
feasibility_flags = []
|
|
710
|
+
first_violation_time = None
|
|
711
|
+
|
|
712
|
+
x_current = x_0.copy()
|
|
713
|
+
|
|
714
|
+
for t in range(horizon):
|
|
715
|
+
# Get control for this time step (use policy if constant, or index if list)
|
|
716
|
+
if isinstance(policy, ControlVector):
|
|
717
|
+
u_t = policy
|
|
718
|
+
elif isinstance(policy, list) and t < len(policy):
|
|
719
|
+
u_t = policy[t]
|
|
720
|
+
else:
|
|
721
|
+
u_t = policy # Fallback
|
|
722
|
+
|
|
723
|
+
# Get disturbance for this time step
|
|
724
|
+
w_t = disturbances[t] if t < len(disturbances) else {}
|
|
725
|
+
|
|
726
|
+
# Evolve state
|
|
727
|
+
x_next = self.dynamics.step(x_current, u_t, w_t)
|
|
728
|
+
trajectory.append(x_next)
|
|
729
|
+
|
|
730
|
+
# Check feasibility
|
|
731
|
+
is_feasible, violations = self.constraint_checker.check_feasible(x_next, u_t)
|
|
732
|
+
feasibility_flags.append(is_feasible)
|
|
733
|
+
|
|
734
|
+
if not is_feasible and first_violation_time is None:
|
|
735
|
+
first_violation_time = t + 1
|
|
736
|
+
logger.debug(f"First constraint violation at t={first_violation_time}: {violations[:2]}")
|
|
737
|
+
|
|
738
|
+
x_current = x_next
|
|
739
|
+
|
|
740
|
+
return trajectory, feasibility_flags, first_violation_time
|
|
741
|
+
|
|
742
|
+
def check_trajectory_feasibility(
|
|
743
|
+
self,
|
|
744
|
+
trajectory: List[StateVector],
|
|
745
|
+
controls: List[ControlVector]
|
|
746
|
+
) -> Tuple[bool, Optional[int]]:
|
|
747
|
+
"""
|
|
748
|
+
Check feasibility of entire trajectory.
|
|
749
|
+
|
|
750
|
+
Args:
|
|
751
|
+
trajectory: List of state vectors
|
|
752
|
+
controls: List of control vectors (one per transition)
|
|
753
|
+
|
|
754
|
+
Returns:
|
|
755
|
+
Tuple[bool, Optional[int]]: (is_feasible, first_violation_time)
|
|
756
|
+
"""
|
|
757
|
+
if len(controls) != len(trajectory) - 1:
|
|
758
|
+
logger.warning(
|
|
759
|
+
f"Trajectory length {len(trajectory)} doesn't match controls length {len(controls)}"
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
for t, x_t in enumerate(trajectory[1:], start=1): # Skip initial state
|
|
763
|
+
u_t = controls[t - 1] if t - 1 < len(controls) else ControlVector()
|
|
764
|
+
is_feasible, violations = self.constraint_checker.check_feasible(x_t, u_t)
|
|
765
|
+
|
|
766
|
+
if not is_feasible:
|
|
767
|
+
return False, t
|
|
768
|
+
|
|
769
|
+
return True, None
|
|
770
|
+
|