# CasADi - 最优控制开源 Python/MATLAB 库3

### 4.7 for 循环等价

#### 4.7.1 映射

N = 4
X = MX.sym("X",1,N)

print(f)

ys = []
for i in range(N):
ys.append(f(X[:,i]))

Y = hcat(ys)
F = Function('F',[X],[Y])
print(F)
f:(i0)->(o0) SXFunction
F:(i0[1x4])->(o0[1x4]) MXFunction


F = f.map(N)
print(F)
map4_f:(i0[1x4])->(o0[1x4]) Map


F = f.map(N,"thread",2)
print(F)


#### 4.7.2. 折叠 Fold

x = x0
for i in range(N):
x = f(x)

F = Function('F',[x0],[x])
print(F)
F:(i0)->(o0) MXFunction


F = f.fold(N)
print(F)
fold_f:(i0)->(o0) MXFunction


x = SX.sym("x")
f0 = Function("f0",[x],[sin(x)])
f1 = Function("f1",[x],[cos(x)])
f2 = Function("f2",[x],[tan(x)])
f_cond = Function.conditional('f_cond', [f0, f1], f2)
print(f_cond)
f_cond:(i0,i1)->(o0) Switch
x = SX.sym('x');
f0 = Function('f0',{x},{sin(x)});
f1 = Function('f1',{x},{cos(x)});
f2 = Function('f2',{x},{tan(x)});
f_cond = Function.conditional('f_cond', {f0, f1}, f2);
disp(f_cond);
f_cond:(i0,i1)->(o0) Switch


x = SX.sym("x")
f_true = Function("f_true",[x],[cos(x)])
f_false = Function("f_false",[x],[sin(x)])
f_cond = Function.if_else('f_cond', f_true, f_false)
print(f_cond)
f_cond:(i0,i1)->(o0) Switch
x = SX.sym('x');
f_true = Function('f_true',{x},{cos(x)});
f_false = Function('f_false',{x},{sin(x)});
f_cond = Function.if_else('f_cond', f_true, f_false);
disp(f_cond);
f_cond:(i0,i1)->(o0) Switch


[1] 对于有自由结束时间的问题，可以通过引入一个额外参数来缩放时间，并用 t 代替从 0 到 1 的无量纲时间变量

## 五、 生成 C 代码

C 代码生成之所以有趣，有以下几个原因：

### 5.1. 生成代码的语法

x = MX.sym('x',2)
y = MX.sym('y')
f = Function('f',[x,y],\
[x,sin(y)*x],\
['x','y'],['r','q'])
f.generate('gen.c')
/* This file was automatically generated by CasADi 3.6.4.
*  It consists of:
*   3) user code: owned by the user
*
*/
#ifdef __cplusplus
extern "C" {
#endif

/* How to prefix internal symbols */
#define _CASADI_NAMESPACE_CONCAT(NS, ID) NS ## ID
#else
#endif

#include <math.h>

#endif

#endif

/* Add prefix to internal symbols */

/* Symbol visibility in DLLs */
#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#else
#endif
#elif defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
#else
#endif
#endif

if (y) {
if (x) {
for (i=0; i<n; ++i) *y++ = *x++;
} else {
for (i=0; i<n; ++i) *y++ = 0.;
}
}
}

/* f:(x[2],y)->(r[2],q[2]) */
/* #0: @0 = input[0][0] */
/* #1: output[0][0] = @0 */
/* #2: @1 = input[1][0] */
w1 = arg[1] ? arg[1][0] : 0;
/* #3: @1 = sin(@1) */
w1 = sin( w1 );
/* #4: @0 = (@1*@0) */
for (i=0, rr=w0, cs=w0; i<2; ++i) (*rr++)  = (w1*(*cs++));
/* #5: output[1][0] = @0 */
return 0;
}

return casadi_f0(arg, res, iw, w, mem);
}

return 0;
}

return 0;
}

}

return 0;
}

}

}

}

switch (i) {
default: return 0;
}
}

switch (i) {
case 0: return "x";
case 1: return "y";
default: return 0;
}
}

switch (i) {
case 0: return "r";
case 1: return "q";
default: return 0;
}
}

switch (i) {
default: return 0;
}
}

switch (i) {
default: return 0;
}
}

if (sz_arg) *sz_arg = 4;
if (sz_res) *sz_res = 3;
if (sz_iw) *sz_iw = 0;
if (sz_w) *sz_w = 3;
return 0;
}

#ifdef __cplusplus
} /* extern "C" */
#endif



f = Function('f',[x],[sin(x)])
g = Function('g',[x],[cos(x)])
C = CodeGenerator('gen.c')
C.generate()


generate 函数和 CodeGenerator 构造函数都将可选的选项字典作为参数，以便自定义代码生成。两个有用的选项是：main（生成主入口）和 mex（生成 mexFunction 入口）：

f = Function('f',[x],[sin(x)])
opts = dict(main=True, \
mex=True)
f.generate('gen.c',opts)


### 5.2 使用生成的代码

[1]，在 Linux/OSX 上，编译就像下发命令一样简单：

gcc -fPIC -shared gen.c -o gen.so

f = external('f', './gen.so')
print(f(3.14))
0.00159265


#### 5.2.2. 从 MATLAB 调用生成的代码

%mex gen.c -largeArrayDims  % Matlab
mex gen.c -DMATLAB_MEX_FILE % Octave

disp(gen('f', 3.14))
1.5927e-03


#### 5.2.3. 从命令行调用生成的代码

# Command line
echo 3.14 3.14 > gen_in.txt
gcc gen.c -o gen
./gen f < gen_in.txt > gen_out.txt
cat gen_out.txt # returns 0.00159265 0.00159265



### 5.3. 生成代码的应用程序接口

#### 5.3.1. 引用计数

void fname_incref(void);
void fname_decref(void);

#### 5.3.2. 输入和输出的数量

casadi_int fname_n_in(void);
casadi_int fname_n_out(void);

#### 5.3.3. 输入和输出的名称

const char* fname_name_in(casadi_int ind);
const char* fname_name_out(casadi_int ind);

#### 5.3.4. 输入和输出的稀疏性模式

const casadi_int* fname_sparsity_in(casadi_int ind);


#### 5.3.5. 内存对象

void* fname_alloc_mem(void);


int fname_init_mem(void* mem);

(重新）初始化内存对象。成功后返回 0；

int fname_free_mem(void* mem);

#### 5.3.6. 工作向量

int fname_work(casadi_int* sz_arg, casadi_int* sz_res, casadi_int* sz_iw, casadi_int* sz_w);


#### 5.3.7. 数值评估

int fname(const double** arg, double** res,
casadi_int* iw, double* w, void* mem);


[1]

## 六、用户自定义函数对象¶

### 6.2 子类化 Callback¶

Callback 类为 FunctionInternal 提供了公共 API，从该类继承与直接从 FunctionInternal 继承效果相同。得益于跨语言多态性，无论是 Python、MATLAB/Octave 还是 C++，都可以实现 Callback 的公开方法。

#### 6.2.1. Python* 语言

class MyCallback(Callback):
def __init__(self, name, d, opts={}):
Callback.__init__(self)
self.d = d
self.construct(name, opts)

# Number of inputs and outputs
def get_n_in(self): return 1
def get_n_out(self): return 1

# Initialize the object
def init(self):
print('initializing object')

# Evaluate numerically
def eval(self, arg):
x = arg[0]
f = sin(self.d*x)
return [f]


# Use the function
f = MyCallback('f', 0.5)
print(f(2))

x = MX.sym("x")
print(f(x))
initializing object
0.841471
f(x){0}



#### 6.2.2. MATLAB¶

classdef MyCallback < casadi.Callback
properties
d
end
methods
function self = MyCallback(name, d)
self.d = d;
construct(self, name);
end

% Number of inputs and outputs
function v=get_n_in(self)
v=1;
end
function v=get_n_out(self)
v=1;
end

% Initialize the object
function init(self)
disp('initializing object')
end

% Evaluate numerically
function arg = eval(self, arg)
x = arg{1};
f = sin(self.d * x);
arg = {f};
end
end
end


% Use the function
f = MyCallback('f', 0.5);
res = f(2);
disp(res)

x = MX.sym('x');
disp(f(x))



#### 6.2.3. C++¶

#include "casadi/casadi.hpp"
class MyCallback : public Callback {
// Data members
double d;
public:
// Constructor
MyCallback(const std::string& name, double d,
const Dict& opts=Dict()) : d(d) {
construct(name, opts);
}

// Destructor
~MyCallback() override {}

// Number of inputs and outputs
casadi_int get_n_in() override { return 1;}
casadi_int get_n_out() override { return 1;}

// Initialize the object
void init() override() {
std::cout << "initializing object" << std::endl;
}

// Evaluate numerically
std::vector<DM> eval(const std::vector<DM>& arg) const override {
DM x = arg.at(0);
DM f = sin(d*x);
return {f};
}
};


int main() {
MyCallback f("f", 0.5);
std::vector<DM> arg = {2};
std::vector<DM> res = f(arg);
std::cout << res << std::endl;
return 0;
}



|
1天前
|

HTTP协议大揭秘！Python requests库实战，让网络请求变得简单高效
【9月更文挑战第13天】在数字化时代，互联网成为信息传输的核心平台，HTTP协议作为基石，定义了客户端与服务器间的数据传输规则。直接处理HTTP请求复杂繁琐，但Python的requests库提供了一个简洁强大的接口，简化了这一过程。HTTP协议采用请求与响应模式，无状态且结构化设计，使其能灵活处理各种数据交换。
24 8
|
5天前
|
JSON API 开发者
Python网络编程新纪元：urllib与requests库，让你的HTTP请求无所不能
【9月更文挑战第9天】随着互联网的发展，网络编程成为现代软件开发的关键部分。Python凭借简洁、易读及强大的特性，在该领域展现出独特魅力。本文介绍了Python标准库中的urllib和第三方库requests在处理HTTP请求方面的优势。urllib虽API底层但功能全面，适用于深入控制HTTP请求；而requests则以简洁的API和人性化设计著称，使HTTP请求变得简单高效。两者互补共存，共同推动Python网络编程进入全新纪元，无论初学者还是资深开发者都能从中受益。
25 7
|
12天前
|

python这些库和框架哪个更好
【9月更文挑战第2天】python这些库和框架哪个更好
28 6
|
12天前
|

python有哪些常用的库和框架
【9月更文挑战第2天】python有哪些常用的库和框架
18 6
|
12天前
|

Python网络爬虫库种类丰富，各具特色。requests 和 urllib 简化了 HTTP 请求，urllib3 提供了线程安全的连接池，httplib2 则具备全面的客户端接口。异步库 aiohttp 可大幅提升数据抓取效率。
33 1
|
15天前
|

Python那些公认好用的库
Python拥有丰富的库，适用于数据科学、机器学习、网络爬虫及Web开发等领域。例如，NumPy和Pandas用于数据处理，Matplotlib和Dash用于数据可视化，Scikit-learn、TensorFlow和PyTorch则助力机器学习。此外，Pillow和OpenCV专长于图像处理，Pydub处理音频，Scrapy和Beautiful Soup则擅长网络爬虫工作
20 4
|
15天前
|

【8月更文挑战第29天】
40 4
|
14天前
|

NumPy 与 SciPy：Python 科学计算库的比较
【8月更文挑战第30天】
40 1
|
15天前
|

Python中的数据可视化：使用Matplotlib库绘制图表
【8月更文挑战第30天】数据可视化是数据科学和分析的关键组成部分，它帮助我们以直观的方式理解数据。在Python中，Matplotlib是一个广泛使用的绘图库，提供了丰富的功能来创建各种类型的图表。本文将介绍如何使用Matplotlib库进行数据可视化，包括安装、基本概念、绘制不同类型的图表以及自定义图表样式。我们将通过实际代码示例来演示如何应用这些知识，使读者能够轻松地在自己的项目中实现数据可视化。
17 0
|
15天前
|

32 0