自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Djinn:一個受 Jinja2 啟發(fā)的代碼生成器和模板語言

開發(fā) 開發(fā)工具
我決定制作一個類似于 Jinja2 的工具,但讓我可以通過使用范圍算法轉(zhuǎn)換數(shù)據(jù)來生成復雜的文件。這個想法非常簡單:一個直接用 D 語言代碼重寫的模板語言。因為它 就是 D 語言,它可以支持 D 語言所能做的一切。

代碼生成器是非常有用的工具。我有時使用 jinja2 的命令行版本來生成高度冗余的配置文件和其他文本文件,但它在轉(zhuǎn)換數(shù)據(jù)方面功能有限。顯然,Jinja2 的作者有不同的想法,而我想要類似于 列表推導list comprehensions 或 D 語言的 可組合范圍composable range 算法之類的東西。

我決定制作一個類似于 Jinja2 的工具,但讓我可以通過使用范圍算法轉(zhuǎn)換數(shù)據(jù)來生成復雜的文件。這個想法非常簡單:一個直接用 D 語言代碼重寫的模板語言。因為它 就是 D 語言,它可以支持 D 語言所能做的一切。我想要一個獨立的代碼生成器,但是由于 D 語言的 mixin 特性,同樣的模板語言可以作為嵌入式模板語言工作(例如,Web 應用程序中的 HTML)。有關該技巧的更多信息,請參閱 ??這篇?? 關于在編譯時使用 mixins 將 Brainfuck 轉(zhuǎn)換為 D 和機器代碼的文章。

像往常一樣,??源碼在 GitLab 上???。??這篇文章中的例子也可以在這里找到??。

Hello world 示例

這是一個演示這個想法的例子:

Hello [= retro("dlrow") ]!
[: enum one = 1; :]
1 + 1 = [= one + one ]

??[= some_expression ]??? 類似于 Jinja2 中的 ??{{ some_expression }}???,它在輸出中呈現(xiàn)一個值。??[: some_statement; :]??? 類似于 ??{% some_statement %}??? ,用于執(zhí)行完整的代碼語句。我更改了語法,因為 D 也大量使用花括號,并且將兩者混合使模板難以閱讀(還有一些特殊的非 D 指令,比如 ??include???,它們被包裹在 ??[<??? 和 ??>]?? 中)。

如果你將上面的內(nèi)容保存到一個名為 ??hello.txt.dj??? 的文件中并運行 ??djinn??? 命令行工具,你會得到一個名為 ??hello.txt?? 的文件,其中包含你可能猜到的內(nèi)容:

Hello world!
1 + 1 = 2

如果你使用過 Jinja2,你可能想知道第二行發(fā)生了什么。Djinn 有一個簡化格式化和空格處理的特殊規(guī)則:如果源代碼行包含 ??[:??? 語句或 ??[<?? 指令但不包含任何非空格輸出,則整行都會被忽略輸出。空行則仍會原樣呈現(xiàn)。

生成數(shù)據(jù)

好的,現(xiàn)在來講一些更實用的東西:生成 CSV 數(shù)據(jù)。

x,f(x)
[: import std.mathspecial;
foreach (x; iota(-1.0, 1.0, 0.1)) :]
[= "%0.1f,%g", x, normalDistribution(x) ]

一個 ??[=??? 和 ??]??? 對可以包含多個用逗號分隔的表達式。如果第一個表達式是一個由雙引號包裹的字符串,則會被解釋為 ??格式化字符串??。下面是輸出結(jié)果:

x,f(x)
-1.0,0.158655
-0.9,0.18406
-0.8,0.211855
-0.7,0.241964
-0.6,0.274253
-0.5,0.308538
-0.4,0.344578
-0.3,0.382089
-0.2,0.42074
-0.1,0.460172
0.0,0.5
0.1,0.539828
0.2,0.57926
0.3,0.617911
0.4,0.655422
0.5,0.691462
0.6,0.725747
0.7,0.758036
0.8,0.788145
0.9,0.81594

制作圖片

這個例子展示了一個圖片的生成過程。??經(jīng)典的 Netpbm 圖像庫定義了一堆圖像格式??,其中一些是基于文本的。例如,這是一個 3 x 3 向量的圖像:

P2 # PGM 格式標識
3 3 # 寬和高
7 # 代表純白色的值(0 代表黑色)
7 0 7
0 0 0
7 0 7

你可以將上述文本保存到名為 ??cross.pgm??? 之類的文件中,很多圖像工具都知道如何解析它。下面是一些 Djinn 代碼,它以相同的格式生成 ??Mandelbrot 集?? 分形:

[:
import std.complex;
enum W = 640;
enum H = 480;
enum kMaxIter = 20;
ubyte mb(uint x, uint y)
{
const c = complex(3.0 * (x - W / 1.5) / W, 2.0 * (y - H / 2.0) / H);
auto z = complex(0.0);
ubyte ret = kMaxIter;
while (abs(z) <= 2 && --ret) z = z * z + c;
return ret;
}
:]
P2
[= W ] [= H ]
[= kMaxIter ]
[: foreach (y; 0..H) :]
[= "%(%s %)", iota(W).map!(x => mb(x, y)) ]

生成的文件大約為 800 kB,但它可以很好地被壓縮為 PNG:

$ # 使用 GraphicsMagick 進行轉(zhuǎn)換
$ gm convert mandelbrot.pgm mandelbrot.png

結(jié)果如下:

解決謎題

這里有一個謎題:

一個 5 行 5 列的網(wǎng)格需要用 1 到 5 的數(shù)字填充,每個數(shù)字在每一行中限使用一次,在每列中限使用一次(即,制作一個 5 行 5 列的拉丁方格Latin square)。相鄰單元格中的數(shù)字還必須滿足所有 ??>?? 大于號表示的不等式。

??幾個月前我使用了 線性規(guī)劃linear programming(LP)??。線性規(guī)劃問題是具有線性約束的連續(xù)變量系統(tǒng)。這次我將使用混合整數(shù)線性規(guī)劃mixed integer linear programming(MILP),它通過允許整數(shù)約束變量來歸納 LP。事實證明,這足以成為 NP 完備的,而 MILP 恰好可以很好地模擬這個謎題。

在上一篇文章中,我使用 Julia 庫 JuMP 來幫助解決這個問題。這次我將使用 ??CPLEX:基于文本的格式??,它受到多個 LP 和 MILP 求解器的支持(如果需要,可以通過現(xiàn)成的工具輕松轉(zhuǎn)換為其他格式)。這是上一篇文章中 CPLEX 格式的 LP:

Minimize
obj: v
Subject To
ptotal: pr + pp + ps = 1
rock: 4 ps - 5 pp - v <= 0
paper: 5 pr - 8 ps - v <= 0
scissors: 8 pp - 4 pr - v <= 0
Bounds
0 <= pr <= 1
0 <= pp <= 1
0 <= ps <= 1
End

CPLEX 格式易于閱讀,但復雜度高的問題需要大量變量和約束來建模,這使得手工編碼既痛苦又容易出錯。有一些特定領域的語言,例如 ??ZIMPL??,用于以高級方式描述 MILP 和 LP。對于許多問題來說,它們非常酷,但最終它們不如具有良好庫(如 JuMP)支持的通用語言或使用 D 語言的代碼生成器那樣富有表現(xiàn)力。

我將使用兩組變量來模擬這個謎題:??v_{r,c}??? 和 ??i_{r,c,v}???。??v_{r,c}??? 將保存 r 行 c 列單元格的值(從 1 到 5)。??i_{r,c,v}?? 是一個二進制指示器,如果 r 行 c 列的單元格的值是 v,則該指示器值為 1,否則為0。這兩組變量是網(wǎng)格的冗余表示,但第一種表示更容易對不等式約束進行建模,而第二種表示更容易對唯一性約束進行建模。我只需要添加一些額外的約束來強制這兩個表示是一致的。但首先,讓我們從每個單元格必須只有一個值的基本約束開始。從數(shù)學上講,這意味著給定行和列的所有指示器都必須為

0,但只有一個值為 1 的例外。這可以通過以下等式強制約束:

[i_{r,c,1} + i_{r,c,2} + i_{r,c,3} + i_{r,c,4} + i_{r,c,5} = 1]

可以使用以下 Djinn 代碼生成對所有行和列的 CPLEX 約束:

\ 單元格只有一個值
[:
foreach (r; iota(N))
foreach (c; iota(N))
:]
[= "%-(%s + %)", vs.map!(v => ivar(r, c, v)) ] = 1
[::]

??ivar()??? 是一個輔助函數(shù),它為我們提供變量名為 ??i??? 的字符串標識符,而 ??vs??? 存儲從 1 到 5 的數(shù)字以方便使用。行和列內(nèi)唯一性的約束完全相同,但在 ??i?? 的其他兩個維度上迭代。

為了使變量組 ??i??? 與變量組 ??v??? 保持一致,我們需要如下約束(請記住,變量組 ??i?? 中只有一個元素的值是非零的):

[i_{r,c,1} + 2i_{r,c,2} + 3i_{r,c,3} + 4i_{r,c,4} + 5i_{r,c,5} = v_{r,c}]

CPLEX 要求所有變量都位于左側(cè),因此 Djinn 代碼如下所示:

\ 連接變量組 i 和變量組 v
[:
foreach (r; iota(N))
foreach (c; iota(N))
:]
[= "%-(%s + %)", vs.map!(v => text(v, ' ', ivar(r, c, v))) ] - [= vvar(r,c) ] = 0
[::]

不等符號相鄰的和左下角值為為 4 單元格的約束寫起來都很簡單。剩下的便是將指示器變量聲明為二進制,并為變量組 ??v??? 設置邊界。加上變量的邊界,總共有 150 個變量和 111 個約束 ??你可以在倉庫中看到完整的代碼??。

GNU 線性規(guī)劃工具集 有一個命令行工具可以解決這個 CPLEX MILP。不幸的是,它的輸出是一個包含了所有內(nèi)容的體積很大的轉(zhuǎn)儲,所以我使用 awk 命令來提取需要的內(nèi)容:

$ time glpsol --lp inequality.lp -o /dev/stdout | awk '/v[0-9][0-9]/ { print $2, $4 }' | sort
v00 1
v01 3
v02 2
v03 5
v04 4
v10 2
v11 5
v12 4
v13 1
v14 3
v20 3
v21 1
v22 5
v23 4
v24 2
v30 5
v31 4
v32 3
v33 2
v34 1
v40 4
v41 2
v42 1
v43 3
v44 5
real 0m0.114s
user 0m0.106s
sys 0m0.005s

這是在原始網(wǎng)格中寫出的解決方案:

這些例子只是用來玩的,但我相信你已經(jīng)明白了。順便說一下,Djinn 代碼倉庫的 ??README.md?? 文件本身是使用 Djinn 模板生成的。

正如我所說,Djinn 也可以用作嵌入在 D 語言代碼中的編譯期模板語言。我最初只是想要一個代碼生成器,得益于 D 語言的元編程功能,這算是一個額外獲得的功能。

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2017-03-20 17:49:21

Java Web模板代碼

2023-08-04 09:00:00

人工智能GPT-4語言模型

2019-01-24 09:46:38

PelicanPython生成器

2012-03-30 09:31:44

WEBCSS

2024-04-07 00:00:01

TypeScript語言REST

2024-06-12 13:40:58

2018-11-19 10:10:51

Python數(shù)據(jù)庫隨機生成器

2009-07-03 09:29:24

KeelKit

2020-09-08 11:21:48

SQL生成器跨庫

2022-03-10 10:48:30

PolyCoder自動代碼生成器語言

2023-05-17 16:02:00

CSS工具代碼生成器

2022-05-19 14:57:30

CSS代碼工具

2023-02-07 16:11:41

2021-07-23 11:24:54

Create Inc開源G代碼生成器

2015-08-25 15:54:17

程序員代碼生成器

2023-05-26 00:14:38

PythonJinJa2

2022-07-25 10:27:36

背景生成器工具前端

2015-09-10 08:45:39

CSS3生成器

2024-08-19 00:00:00

表單生成器開發(fā)開源

2025-01-08 08:00:20

點贊
收藏

51CTO技術棧公眾號