You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiny中actionButton触发递归函数引发C栈溢出错误求助

解决Shiny应用中Gauss-Jordan消元的无限递归问题

你遇到的C stack usage too close to the limit错误确实是无限递归导致的——问题出在你重复定义了同名的mat_list对象,而且第二个eventReactive内部又调用了mat_list(),这就形成了循环调用:每次触发play按钮,eventReactive会调用自己,不断递归直到栈溢出。

要解决这个问题,我们需要用可变的响应式状态容器(reactiveVal)来追踪当前的矩阵状态,而不是用覆盖式的reactive/eventReactive定义。下面是具体的调整方案:

核心思路

  1. 用reactiveVal保存当前的变换矩阵A和单位矩阵I的状态,这个容器可以被动态更新。
  2. 监听用户修改输入矩阵或切换维度的事件,重置状态容器的初始值。
  3. 监听play按钮的点击事件,取出当前状态,执行一步Gauss-Jordan消元,然后更新状态容器。
  4. 让renderTable依赖这个状态容器,这样无论是输入变化还是点击按钮,表格都会自动更新。

修正后的完整代码

library(shiny)
library(shinythemes)
library(shinyMatrix)
library(plotly)
library(stringr)

# 假设你的apply_gauss_jordan_3d函数已经实现(示例逻辑)
apply_gauss_jordan_3d <- function(A, I) {
  # 这里写实际的一步消元逻辑,示例仅做简单演示
  if (A[1,1] == 0) {
    # 交换行(示例操作)
    temp_row <- A[1,]
    A[1,] <- A[2,]
    A[2,] <- temp_row
    
    temp_row_I <- I[1,]
    I[1,] <- I[2,]
    I[2,] <- temp_row_I
  } else {
    # 归一化第一行(示例操作)
    factor <- A[1,1]
    A[1,] <- A[1,] / factor
    I[1,] <- I[1,] / factor
  }
  list(A, I)
}

# Create user interface
ui <- fluidPage(
  theme = shinytheme("cerulean"),
  titlePanel(
    headerPanel("Linear Transformations")
  ),
  withMathJax(),
  sidebarLayout(
    sidebarPanel(
      radioButtons(
        "dimension",
        label = "Choose number of dimensions",
        choices = c("2D", "3D"),
        selected = "2D"
      ),
      matrixInput(
        "transform_mat",
        label = "Input the transformation matrix",
        value = matrix(c(1, 0, 0, 1), nrow = 2, ncol = 2, byrow = FALSE),
        rows = list(names = FALSE),
        cols = list(names = FALSE),
        class = "numeric",
        copy = TRUE,
        paste = TRUE
      )
    ),
    mainPanel(
      tabsetPanel(
        type = "tabs",
        tabPanel("Plot", plotlyOutput("plot")),
        tabPanel("Null Space", verbatimTextOutput("null_space"), plotlyOutput("null_space_plot")),
        tabPanel("Determinant", uiOutput("determinant")),
        tabPanel(
          "Gauss-Jordan",
          tableOutput("gauss_matrix"),
          tableOutput("gauss_identity"),
          actionButton("rewind", "", icon = icon("fast-backward")),
          actionButton("play", "", icon = icon("play")),
          actionButton("advance", "", icon = icon("fast-forward"))
        )
      )
    )
  )
)

# Define server function
server <- function(input, output, session) {
  # 初始化响应式状态容器,保存当前的A和I矩阵
  current_mats <- reactiveVal()
  
  # 监听输入变化(矩阵修改/维度切换),重置状态
  observeEvent(c(input$dimension, input$transform_mat), {
    dim <- as.numeric(str_remove(input$dimension, "D"))
    initial_A <- input$transform_mat
    initial_I <- diag(dim)
    current_mats(list(initial_A, initial_I))
  }, ignoreInit = FALSE) # ignoreInit=FALSE确保初始化时就触发
  
  # 监听play按钮,执行一步消元并更新状态
  observeEvent(input$play, {
    # 获取当前状态
    current <- current_mats()
    current_A <- current[[1]]
    current_I <- current[[2]]
    
    # 执行一步消元(注意这里要传入正确的A和I,之前你的代码传了两次A)
    new_mats <- apply_gauss_jordan_3d(current_A, current_I)
    
    # 更新状态容器
    current_mats(new_mats)
  })
  
  # 渲染变换矩阵表格
  output$gauss_matrix <- renderTable({
    current_mats()[[1]]
  }, colnames = FALSE)
  
  # 渲染单位矩阵(消元后的逆矩阵)表格
  output$gauss_identity <- renderTable({
    current_mats()[[2]]
  }, colnames = FALSE)
  
  # 其他模块的代码(Plot/Null Space/Determinant)可以保留原逻辑
}

# Run shiny application
shinyApp(ui, server)

关键调整说明

  1. 用reactiveVal替代重复的mat_list:current_mats是一个可变的响应式变量,专门用来保存当前的矩阵状态,避免了递归调用的问题。
  2. 修正apply_gauss_jordan_3d的参数:之前你错误地传入了两次变换矩阵,现在改为传入当前的A和I矩阵,符合函数的输入要求。
  3. 明确状态触发逻辑:用户修改输入时重置状态,点击按钮时更新状态,两个逻辑完全分离,不会互相干扰。

这样调整后,你的应用就能正常响应输入变化和按钮点击,不会再出现无限递归导致的栈溢出问题了。

内容的提问来源于stack exchange,提问作者ramonmb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:44:06