在VBA中使用行parsing器

我试图使用求解器来find182个单元的根,每个单元只依赖于另一个variables,输出单元从O2到O183,可变单元从P2到P183。 我正在尝试更改可变单元格以使输出单元等于1.代码有效,但结果不收敛。 因为我只想要一个固定值1,所以我没有设置MaxMin值。 代码是:

Sub Solver() Dim setcellrange As Range, bychangerange As Range Dim i As Long For i = 3 To 5 Set setcellrange = Sheets("AshfordPierce").Cells(i, 15) Set bychangerange = Sheets("AshfordPierce").Cells(i, 16) SolverReset SolverOk SetCell:=setcellrange.Address, ValueOf:=1, ByChange:=bychangerange.Address, Engine:=1, EngineDesc:="GRG NONLINEAR" SolverSolve Next i End Sub 

当我使用VBA的解算器function时,它工作,但VBA结果不会收敛。 任何帮助表示赞赏。

注意:我将使用这个post来突出显示几个挑战,并希望在VBA中使用Solver的最佳实践。 请随时让我知道,如果有什么需要更新。


告诉解算器使用什么单元格。

似乎(几乎)所有Solver的参数都是Varianttypes的。 这可能会导致您相信您在提供信息方面有很大的灵活性。 事实certificate,你需要提供精心devise的文本string。

使用SolverSave作为示例,根据MS文档,您必须指定SaveArea,并且如果SaveArea与活动工作表不在同一张工作表上,则SaveArea必须包含工作表名称。

这工作:

 SolverSave SaveArea:="Sheet2!A1" 

事实上,所有的MS文档都在其示例中使用了string文字。

这工作:

 SolverSave SaveArea:="Sheet2!A1:A4" 

只要保存只需要四行来存储其数据,通常情况下,但不总是如此。

这不起作用:

 Set SaveRng = Sheets("Sheet2").Range("A1") SolverSave SaveArea:=SaveRng 

它不会抛出一个错误。 它将Sheet2中的单元格A1中的某些信息放入活动工作表中的所有其他位置。

这不起作用:

 Set SaveRng = Sheets("Sheet2").Range("A1:A4") SolverSave SaveArea:=SaveRng 

它会在SolverSave中引发types不匹配错误。

这是否工作:

 Set SaveRng = Sheets("Sheet2").Range("A1") SaveAddress = Split(SaveRng.Address(external:=True), "[")(0) & Split(SaveRng.Address(external:=True), "]")(1) SolverSave SaveArea:=SaveAddress 

上面是我可以find一个最简洁的方式来build立一个范围的完整地址,包括工作表名称和需要时的单引号“'”。 (为了您的调查 – 为什么SaveRng.Address不能工作?)

我build议使用最后的方法(上面)为每个求解例程与参数需要一个地址。 默认情况下,Solver期望事情在ActiveSheet上,这可能会导致意外的行为。


SolverReset – 危险。

看到这个post关于SolverReset和SolverSolve的组合设置你的计算模式为手动(并把它留在那里)。

SolverReset将所有求解器选项都设置为默认值。 这可以用SolverLoad来完成(假设你有一组保存的缺省值),或者用SolverGet / SolverOptions来pipe理它们。

不要使用SolverReset。


SolverOK – 求解器大多好。

在录制macros时,为了得到一个Solver VBA代码的例子,如果你select默认值,你将得到“Engine:= 1”和“EngineDesc:=”GRG Nonlinear“”。 根据MS文档 ,设置Engine或EngineDesc的值就像在Solver Parameters对话框的下拉列表中select一个值。 它还表示Engine:= 1对应于Simplex LP方法, 而不是 GRG Nonlinear。 在设定这两个参数时似乎有冲突的机会。

当testing这个代码…

 Sub mySolve() Dim SetRng As Range, ChgRng As Range Dim SetAddr As String, ChgAddr As String Dim i As Long For i = 2 To 4 Set SetRng = Sheets("Sheet1").Cells(i, 5) Set ChgRng = Sheets("Sheet1").Cells(i, 4) SetAddr = Split(SetRng.Address(external:=True), "[")(0) & Split(SetRng.Address(external:=True), "]")(1) ChgAddr = Split(ChgRng.Address(external:=True), "[")(0) & Split(ChgRng.Address(external:=True), "]")(1) SolverOk SetCell:=SetAddr, MaxMinVal:=3, _ ValueOf:=i, ByChange:=ChgAddr, _ Engine:=1, EngineDesc:="GRG NONLINEAR" SolverSolve UserFinish:=True Next i End Sub 

第二行,第三行和第四行不是一次解决问题,而是三次解决了第四行的问题。 这是使用此代码之前解决的最后一个问题。 它的行为就好像SolverOK从不更新SetCell,ValueOf或ByChange值。 没有错误被抛出。

但是,testing此代码(删除EngineDesc),所有行为如预期…

 Sub mySolve() Dim SetRng As Range, ChgRng As Range Dim SetAddr As String, ChgAddr As String Dim i As Long For i = 2 To 4 Set SetRng = Sheets("Sheet1").Cells(i, 5) Set ChgRng = Sheets("Sheet1").Cells(i, 4) SetAddr = Split(SetRng.Address(external:=True), "[")(0) & Split(SetRng.Address(external:=True), "]")(1) ChgAddr = Split(ChgRng.Address(external:=True), "[")(0) & Split(ChgRng.Address(external:=True), "]")(1) SolverOk SetCell:=SetAddr, MaxMinVal:=3, _ ValueOf:=i, ByChange:=ChgAddr, _ Engine:=1 SolverSolve UserFinish:=True Next i End Sub 

我build议只设置引擎或EngineDesc之一,而不是两者。


SolverSave – 解释你的结果

根据MS文档 ,SolverSave将Solverconfiguration保存在一列信息中。 根据我的经验,这一列通常是4行。

让我解释一下运行这个代码的结果

 Sub mySolve3() Dim SetRng As Range, ChgRng As Range, SavRng As Range Dim SetAddr As String, ChgAddr As String, SavAddr As String Dim iLoop As Long For iLoop = 2 To 4 Set SetRng = Worksheets("Sheet1").Cells(iLoop, 5) Set ChgRng = Worksheets("Sheet1").Cells(iLoop, 4) Set SavRng = Worksheets("Sheet2").Cells(1, iLoop - 1) SetAddr = Split(SetRng.Address(external:=True), "[")(0) & Split(SetRng.Address(external:=True), "]")(1) ChgAddr = Split(ChgRng.Address(external:=True), "[")(0) & Split(ChgRng.Address(external:=True), "]")(1) SavAddr = Split(SavRng.Address(external:=True), "[")(0) & Split(SavRng.Address(external:=True), "]")(1) SolverOk SetCell:=SetAddr, MaxMinVal:=3, ValueOf:=(iLoop - 1), ByChange:=ChgAddr, Engine:=1 SolverSolve UserFinish:=True SolverSave SaveArea:=SavAddr Next iLoop End Sub 

此代码将保存在Sheet 2中的列A,B和C中的三个不同求解器运行的设置。

它运行后,在Sheet2上:单元格A1包含=$E$2=1 ,单元格B1包含=$E$3=2 ,单元格C1包含=$E$4=3 。 SolverSave输出中的第一行是SetCell地址(您可以在SolverOK中指定),在我的情况下,将其设置为ValueOf值(您将在SolverOK中指定)。

单元格A2包含=COUNT($D$2) ,单元格B2包含=COUNT($D$3) ,单元格C2包含=COUNT($D$4) 。 SolverSave输出中的第二行是ByChange地址(您将在SolverOK中指定)。 需要更多的调查来了解为什么使用COUNT函数。

单元格A3,B3和C3包含

={32767,32767,0.000001,0.01,FALSE,FALSE,FALSE,1,2,1,0.0001,TRUE}

通过检查,看起来这是SolverGet中前12个TypeNum值的数组 。 使用SolverGet来检索这些值,而不是32767,你会得到2147483647 – 我期望他们有一些数据types的内部问题。

单元格A4,B4和C4都包含

={0,0,1,100,0,FALSE,FALSE,0.075,0,0,FALSE,30}

同样,通过检查,看起来这是SolverGet中最后12个TypeNum值的数组。 由于SolverGet有29个TypeNum,所以似乎有5个不可用。 然而,SolverOptions只有21个参数。

使用SolverSave保存configuration后,可以修改单元格的内容,并使用SolverLoad来更改Solverconfiguration(而不是SolverOK)。


我原来对发布的问题的答案继续下面…


我需要更多地研究Solver。 有几个片状的东西正在进行。 我能够使用VBA中的循环进行以下工作。

从这开始…

在这里输入图像说明

我得到了这些结果…

在这里输入图像说明

使用这个代码…

 Sub mySolve() Dim LoadRng As Range Dim i As Long Set LoadRng = Sheets("Sheet1").Range(Cells(1, 7), Cells(4, 7)) For i = 2 To 4 LoadRng.Cells(1, 1).Value = "=$E$" & i & "=1" LoadRng.Cells(2, 1).Value = "=COUNT($D$" & i & ")" LoadRng.Cells(3, 1).Value = "={32767,32767,0.000001,0.01,FALSE,FALSE,FALSE,1,2,1,0.0001,TRUE}" LoadRng.Cells(4, 1).Value = "={0,0,1,100,0,FALSE,FALSE,0.075,0,0,FALSE,30}" SolverLoad LoadArea:=LoadRng.Address SolverSolve UserFinish:=True SolverFinish KeepFinal:=1 Next i End Sub 

事情要诊断:

  • SolverReset导致了一些非常奇怪的行为 – 使用它时,随后调用SolverSolve导致Excel翻转到手动计算。
  • 对SolverOK的第一个电话会解决问题,但随后的电话将不会修改问题。
  • SolverAdd,SolverChange等影响约束,但不(显然)的基本问题设置。