0

我正在尝试将我必须的命令行代码传输到带有
GUI 的更可视化的程序中,以便更轻松地使用。原始代码在 C++ 中,所以我使用
Visual Studio Express 2012 中提供的 Visual C++,但我在理解“新”
托管 C++/CLI 处理对象的方式时遇到问题。作为 CLI 和托管 C++ 的新手,我想知道
是否有人可以解释我做错了什么,以及为什么它不起作用。现在这里是
代码和问题的描述。

该程序本质上是一个优化程序:

  • 一个系统中有多个盒子(模式),每个模式,取决于它的类型,都有
    一些数值系数来控制它的行为和它对外部
    激励的响应方式。
  • 该程序要求用户指定盒子的数量和每个盒子的类型。
  • 然后尝试找到使
    系统响应与实验获得的响应之间的差异最小化的数值系数。

因此,UI 具有让用户打开实验结果文件、指定
模式数量和指定每种模式类型的方法。然后,用户可以
通过单击启动按钮来启动处理功能,启动后台工作程序。

按照MSDN中给出的示例,我创建了一个执行该工作的类:

ref class curveFit
{
public: ref class CurrentState{
        public:
            int percentage;
            int iterationNo;
            int stage;
            bool done;
            multimode systemModel;
        };

public:
    int modes;
    int returncode;

    array<double> ^expExcitations;
    array<double> ^expResults;

    multimode systemModel;

private:
    void fcn(int, int, double*, double*, int*);
    double totalError(std::vector<double> &);

public:
    delegate void fcndelegate(int, int, double*, double*, int*);

public:
    curveFit(void);
    curveFit^ fit(System::ComponentModel::BackgroundWorker^, System::ComponentModel::DoWorkEventArgs^, Options^);
};

multimode只是一个容器类:不同盒子的列表。

ref class multimode
{
private:
    Collections::Generic::List<genericBoxModel ^>^ models;
    int modes;

public:
    multimode(void);
    multimode(const multimode%);

    int modeNo(void);
    void Add(genericBoxModel^);
    void Clear();

    genericBoxModel^ operator[](int);
    multimode% operator=(const multimode%);

    double result(double);

    bool isValid();

    std::vector<double> MapData();
    void MapData(std::vector<double> &);
};

multimode::multimode(void)
{
    models = gcnew Collections::Generic::List<genericBoxModel ^>();
    modes = 0;
}

multimode::multimode(const multimode% rhs)
{
    models = gcnew Collections::Generic::List<genericBoxModel ^>();
    for(int ind = 0; ind < rhs.modes; ind++)
        models->Add(rhs.models[ind]);
    modes = rhs.modes;
}

int multimode::modeNo(void)
{
    return modes;
}

void multimode::Add(genericBoxModel^ model)
{
    models->Add(model);
    modes++;
}

void multimode::Clear()
{
    models->Clear();
    modes = 0;
}

genericBoxModel^ multimode::operator[](int ind)
{
    return models[ind];
}

multimode% multimode::operator=(const multimode% rhs)
{
    models->Clear();
    for(int ind = 0; ind < rhs.modes; ind++)
        models->Add(rhs.models[ind]);
    modes = rhs.modes;

    return *this;
}

double multimode::result(double excitation)
{
    double temp = 0.0;

    for(int ind = 0; ind < modes; ind++)
        temp += models[ind]->result(excitation);

    return temp;
}

bool multimode::isValid()
{
    bool isvalid = true;

    if(modes < 1)
         return false;

    for(int ind = 0; ind < modes; ind++)
        isvalid = (isvalid && models[ind]->isValid());

    return isvalid;
}

std::vector<double> multimode::fullMap()
{
    //Map the model coefficients to a vector of doubles
    ...
}

void multimode::fullMap(std::vector<double> &data)
{
    //Map a vector of doubles to the model coefficients
    ...
}

并且genericBoxModel是所有盒子模型都基于的抽象类。

curvefit::fit函数根据传递给它的选项进行优化:

curveFit^ curveFit::fit(System::ComponentModel::BackgroundWorker^ worker, System::ComponentModel::DoWorkEventArgs^ e, Options^ opts)
{
    fcndelegate^ del = gcnew fcndelegate(this, &curveFit::fcn);
    std::vector<double> data;

    CurrentState^ state = gcnew CurrentState;
    state->done = false;
    state->stage = 0;
    state->percentage = 0;
    state->systemModel = systemModel;
    worker->ReportProgress(state->percentage, state);

    switch(opts->optimizationMethod)
    {
        case 0:
            while(iterationNo < maxIterations)
            {
                data = systemModel.MapData();
                OptimizationMethod0::step(some_parameters, data, (optmethods::costfunction)Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(del).ToPointer());
                systemModel.MapData(data);
                iterationNo++;
                state->percentage = 0;
                state->systemModel = systemModel;
                worker->ReportProgress(state->percentage, state);
            }
        ...
    }
}

我在状态内传递系统模型,以便我可以
在屏幕上显示最新步骤的结果,这不起作用,但这是另一个问题:-)

启动按钮curvefit::fit在初始化系统模型后调用该函数:

private: System::Void btnStart_Click(System::Object^  sender, System::EventArgs^  e) {
    systemModel.Clear();
    for(int mode = 0; mode < modes; mode++)
    {
        switch(model)
        {
        case 0:
            systemModel.Add(gcnew model0);
            systemModel[mode]->coefficients[0] = 100.0 / double(mode + 1);
            ...
            break;
        ...
        }
    }
    btnStart->Enabled = false;
    stStatusText->Text = "Calculating!";
    Application::UseWaitCursor = true;
    curveFit^ cf = gcnew curveFit;
    fitCurve->RunWorkerAsync(cf);
}

private: System::Void fitCurve_DoWork(System::Object^  sender, System::ComponentModel::DoWorkEventArgs^  e) {
    System::ComponentModel::BackgroundWorker^ worker;
    worker = dynamic_cast<System::ComponentModel::BackgroundWorker^>(sender);

    curveFit^ cf = safe_cast<curveFit^>(e->Argument);
    cf->expExcitations = gcnew array<double>(expExcitations.Count);
    expExcitations.CopyTo(cf->expExcitations);
    cf->expResults = gcnew array<double>(expResults.Count);
    expResults.CopyTo(cf->expResults);
    cf->systemModel = systemModel;
    cf->modes = modes;

    e->Result = cf->fit(worker, e, options);
}

这完美!但是,为了使优化过程更快更
成功,我想使用之前优化的结果作为
下一次运行的初始猜测(如果可能的话):

multimode oldmodel(systemModel);
systemModel.Clear();
for(int mode = 0; mode < modes; mode++)
{
    switch(model)
    {
    case 0:
        if(mode < oldmodel.modeNo() && oldmodel.isValid() && (oldmodel[mode]->model == 0))
            systemModel.Add(oldmodel[mode]);
        else
        {
            systemModel.Add(gcnew model0);
            systemModel[mode]->coefficients[0] = 100.0 / double(mode + 1);
            ...
        }
        break;
    ...

现在,我的问题是,在此更改之后,消息似乎没有
正确传递:第一次单击开始按钮时,一切正常,
但从那时起,如果语句systemModel.Add(oldmodel[mode]);被执行,
结果仍然是与最初的猜测相同,并且在fit
调用函数后不会更新。

那么,为什么这两行(Add(oldmodel[mode])Add(gcnew model0))会给出
如此不同的结果呢?

4

0 回答 0