整数线性规划求解工具 Integer Set Library
isl是一个用于多面体模型调度实现的c/c++库。通过isl,我们可以对模型进行自动的调度,循环优化等。
编译
ISL,Integer Set Library
版本0.22.1,http://isl.gforge.inria.fr/
README关于编译的部分说了
./configure
make
make install
使用./configure --help阅读后针对本地环境,使用
./configure --prefix=/opt/isl --enable-shared=yes --enable-static=yes \
CC=/opt/gcc/bin/gcc \
CFLAGS="-O3 -I/opt/gmp/include" \
LDFLAGS="-L/opt/gmp/lib -Wl,--rpath=/opt/gmp/lib" \
CXX=/opt/gcc-10.2.0/bin/g++ \
CXXFLAGS="-I/opt/gmp/include" \
PYTHON=/opt/python3/bin/python3 \
--enable-fast-install=no --with-gnu-ld
make
make install
isl内部对象介绍
- 1.isl_ctx对象的创建(初始化):
整数集和关系的所有操作都在的上下文中发生isl_ctx。给定isl_ctx只能在单个线程中使用。一个函数的所有参数都必须在同一上下文中分配。当前没有功能可用于将对象从一个移动isl_ctx到另一个isl_ctx。这意味着当前无法安全地将对象从一个线程移动到另一个线程,除非整个线程isl_ctx都移动了。
一个isl_ctx可以使用分配isl_ctx_alloc和使用中解脱出来isl_ctx_free。在isl_ctx释放之前,应释放内分配的所有对象isl_ctx。
isl_ctx 对象就像一根线一样把上下文关系(对象)连接起来。
isl_ctx *isl_ctx_alloc();
void isl_ctx_free(isl_ctx *ctx);
测试:
isl_ctx *isl = isl_ctx_alloc(); // 创建对象
cout << isl << endl;
isl_ctx_free(isl); // 释放
输出是一个地址值,可以看出来该指针指向一个对象。
同时,我们还可以为 isl_ctx 对象指定低级 op 数量的范围(bound)。例如:
void isl_ctx_set_max_operations(isl_ctx *ctx,
unsigned long max_operations);
unsigned long isl_ctx_get_max_operations(isl_ctx *ctx);
void isl_ctx_reset_operations(isl_ctx *ctx);
上面说了ctx相当于线将各种对象连接起来,那么我们还可以通过上下文对象来得到ctx:
#include <isl/val.h>
isl_ctx *isl_val_get_ctx(__isl_keep isl_val *val);
isl_ctx *isl_multi_val_get_ctx(
__isl_keep isl_multi_val *mv);
#include <isl/id.h>
isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id);
isl_ctx *isl_multi_id_get_ctx(
__isl_keep isl_multi_id *mi);
#include <isl/local_space.h>
isl_ctx *isl_local_space_get_ctx(
__isl_keep isl_local_space *ls);
#include <isl/set.h>
isl_ctx *isl_set_list_get_ctx(
__isl_keep isl_set_list *list);
#include <isl/aff.h>
isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff);
isl_ctx *isl_multi_aff_get_ctx(
__isl_keep isl_multi_aff *maff);
isl_ctx *isl_pw_aff_get_ctx(__isl_keep isl_pw_aff *pa);
isl_ctx *isl_pw_multi_aff_get_ctx(
__isl_keep isl_pw_multi_aff *pma);
isl_ctx *isl_multi_pw_aff_get_ctx(
__isl_keep isl_multi_pw_aff *mpa);
isl_ctx *isl_union_pw_aff_get_ctx(
__isl_keep isl_union_pw_aff *upa);
isl_ctx *isl_union_pw_multi_aff_get_ctx(
__isl_keep isl_union_pw_multi_aff *upma);
isl_ctx *isl_multi_union_pw_aff_get_ctx(
__isl_keep isl_multi_union_pw_aff *mupa);
#include <isl/id_to_ast_expr.h>
isl_ctx *isl_id_to_ast_expr_get_ctx(
__isl_keep isl_id_to_ast_expr *id2expr);
#include <isl/point.h>
isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt);
#include <isl/vec.h>
isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec);
#include <isl/mat.h>
isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat);
#include <isl/vertices.h>
isl_ctx *isl_vertices_get_ctx(
__isl_keep isl_vertices *vertices);
isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex);
isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell);
#include <isl/flow.h>
isl_ctx *isl_restriction_get_ctx(
__isl_keep isl_restriction *restr);
isl_ctx *isl_union_access_info_get_ctx(
__isl_keep isl_union_access_info *access);
isl_ctx *isl_union_flow_get_ctx(
__isl_keep isl_union_flow *flow);
#include <isl/schedule.h>
isl_ctx *isl_schedule_get_ctx(
__isl_keep isl_schedule *sched);
isl_ctx *isl_schedule_constraints_get_ctx(
__isl_keep isl_schedule_constraints *sc);
#include <isl/schedule_node.h>
isl_ctx *isl_schedule_node_get_ctx(
__isl_keep isl_schedule_node *node);
#include <isl/ast_build.h>
isl_ctx *isl_ast_build_get_ctx(
__isl_keep isl_ast_build *build);
#include <isl/ast.h>
isl_ctx *isl_ast_expr_get_ctx(
__isl_keep isl_ast_expr *expr);
isl_ctx *isl_ast_node_get_ctx(
__isl_keep isl_ast_node *node);
#include <isl/stride_info.h>
isl_ctx *isl_stride_info_get_ctx(
__isl_keep isl_stride_info *si);
#include <isl/fixed_box.h>
isl_ctx *isl_fixed_box_get_ctx(
__isl_keep isl_fixed_box *box);
- 2.返回的结果
isl isl_size对返回非负值(通常是数字或位置)的函数使用特殊的返回类型。除了常规的非负返回值外,isl_size_error还可能返回一个特殊的(负)值,表明出错。
isl对于返回布尔值或原则上不返回任何值的函数,它也使用两种特殊的返回类型。特别是,该isl_bool类型具有三个可能的值:(isl_bool_true一个正整数),表示true或yes;isl_bool_false(整数值零),表示false或no;和isl_bool_error(负整数值),表示出了点问题。在上定义了以下操作isl_bool。该函数isl_bool_not可以被用于否定的isl_bool,其中的否定isl_bool_error是isl_bool_error一次。该函数isl_bool_ok将整数转换为isl_bool。任何非零值的收益率isl_bool_true和零收益率isl_bool_false。
bool
int a = 0;
isl_bool result = isl_bool_ok(a);
cout << result << endl;
输出结果为0
- 3.isl_val对象
一个 isl_val 对象表示整数值,有理值或三个特殊值之一,即无穷大,负无穷大和正无穷大。可以使用以下功能创建一些预定义的值:
#include <isl/val.h>
__isl_give isl_val *isl_val_zero(isl_ctx *ctx);
__isl_give isl_val *isl_val_one(isl_ctx *ctx);
__isl_give isl_val *isl_val_negone(isl_ctx *ctx);
__isl_give isl_val *isl_val_nan(isl_ctx *ctx);
__isl_give isl_val *isl_val_infty(isl_ctx *ctx);
__isl_give isl_val *isl_val_neginfty(isl_ctx *ctx);
测试:
isl_val * val = isl_val_zero(isl);
cout << val << endl;
输出:
0x93c6080
可以使用以下函数创建特定的整数值:
#include <isl/val.h>
__isl_give isl_val *isl_val_int_from_si(isl_ctx *ctx,
long i);
__isl_give isl_val *isl_val_int_from_ui(isl_ctx *ctx,
unsigned long u);
__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx,
size_t n, size_t size, const void *chunks);
一个isl_val可以使用下面的函数来修改:
#include <isl/val.h>
__isl_give isl_val *isl_val_set_si(__isl_take isl_val *v,
long i);
可以使用以下功能复制和释放 isl_val 。
#include <isl/val.h>
__isl_give isl_val *isl_val_copy(__isl_keep isl_val *v);
__isl_null isl_val *isl_val_free(__isl_take isl_val *v);
对于这样的数值对象我们还可以对其进行一元运算、二元运算等,具体运算函数可以参考文档。
- 3.集合(set)与关系或映射(map)
isl使用六种类型的代表集合和关系的对象,
isl_basic_set,
isl_basic_map,
isl_set,
isl_map,
isl_union_set 和
isl_union_map(这些其实都是对象)。
isl_basic_set和isl_basic_map分别代表可仿射约束的集合和关系,而isl_set和isl_map分别代表isl_basic_sets和isl_basic_maps 的并集。但是,所有isl_basic_sets或isl_basic_maps都必须居住在同一空间中。isl_union_sets和isl_union_maps表示isl_sets或isl_maps在不同空间中的并集,如果空间的维数和/或名称不同,则它们被认为是不同的(请参见“空间”)。集和关系(映射)之间的区别在于,set具有一组变量,而map具有两组变量,即输入变量和输出变量。
- 4.错误处理
isl在触发运行时错误时,支持不同的反应方式。例如,如果isl_map_intersect用两个具有不兼容空间的映射调用诸如之类的函数,则会出现运行时错误。有三种对错误做出反应的方式:警告,继续或中止。
默认行为是警告。在这种模式下,isl打印警告,将最后一个错误存储在相应isl_ctx的错误中,触发错误的函数将返回一个值,指示发生了某些错误。如果函数返回指针,则该值为NULL。在返回一个功能的情况下isl_size,isl_bool或者isl_stat,这个值isl_size_error,isl_bool_error或isl_stat_error。错误不会破坏内部状态,因此可以继续使用isl。isl还提供了读取上一个错误的功能,包括特定的错误消息,发生错误的isl源文件和行号,以及重置有关上一个错误的所有信息。最后的错误仅用于提供信息。它的存在不会改变的行为isl。因此,重新设置错误并不需要继续使用isl,而只是为了观察新的错误。
- 5.isl_id对象
标识符用于识别单个维度和维度元组。它们由一个可选的名称和一个可选的用户指针(代表该id对象标识哪个对象)组成。但是,名称和用户指针不能都为NULL。具有相同名称但指针值不同的标识符被认为是不同的。同样,具有不同名称但指针值相同的标识符也被认为是不同的。相同的标识符使用相同的对象表示。因此,可以使用==运算符测试成对的标识符是否相等。可以使用以下功能构造,复制,释放,检查和打印标识符。
#include <isl/id.h>
__isl_give isl_id *isl_id_alloc(isl_ctx *ctx,
__isl_keep const char *name, void *user);
__isl_give isl_id *isl_id_set_free_user(
__isl_take isl_id *id,
void (*free_user)(void *user));
__isl_give isl_id *isl_id_copy(isl_id *id);
__isl_null isl_id *isl_id_free(__isl_take isl_id *id);
void *isl_id_get_user(__isl_keep isl_id *id);
__isl_keep const char *isl_id_get_name(__isl_keep isl_id *id);
__isl_give isl_printer *isl_printer_print_id(
__isl_take isl_printer *p, __isl_keep isl_id *id);
使用示例:
isl_set *sum = isl_set_sum(set, set2); // 表示对set、set2这两个集合对象进行加法
isl_id *ids = isl_id_alloc(ctx, "sum", sum);// 定义一个id指向sum
char *str_id = isl_id_to_str(ids);
printf("id:%s\n", str_id);
最后输出如下,代表一个地址值:
id:sum@0x993a9e0
- 6.isl_space对象
每当从头开始创建新的set,map或类似对象时,都需要使用来指定其所处的空间isl_space。
每个空间包含零个或多个参数,以及零个,一个或两个元组的 set 或输入/输出维。参数和尺寸由isl_dim_type和标识。类型isl_dim_param是指参数,类型isl_dim_set是指设置维(对于具有单个元组的空间)和类型isl_dim_in,而类型isl_dim_out是指输入和输出维(对于具有两个元组的空间)。局部空间也包含类型的尺寸isl_dim_div。注意,参数仅由其在给定对象中的位置来标识。在不同的对象之间,参数(通常)由其名称或标识符标识。只有未命名的参数才能通过它们在对象之间的位置来标识。不建议使用未命名的参数。
对space的基本操作如下:
#include <isl/space.h>
__isl_give isl_space *isl_space_unit(isl_ctx *ctx);
__isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
unsigned nparam, unsigned n_in, unsigned n_out);//带进带出的专用于map
__isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx,
unsigned nparam);
__isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
unsigned nparam, unsigned dim);
__isl_give isl_space *isl_space_copy(__isl_keep isl_space *space);
__isl_null isl_space *isl_space_free(__isl_take isl_space *space);
需要使用isl_space_unit或创建用于创建参数域的空间isl_space_params_alloc。对于其他集合,需要使用来创建空间isl_space_set_alloc,而对于关系而言,需要使用来创建空间isl_space_alloc。使用的isl_space_params_alloc,isl_space_set_alloc并且isl_space_alloc因为它们允许引进未命名参数是不鼓励。
要检查给定空间是集合空间还是映射空间,还是参数空间,请使用以下函数:
#include <isl/space.h>
isl_bool isl_space_is_params(__isl_keep isl_space *space);
isl_bool isl_space_is_set(__isl_keep isl_space *space);
isl_bool isl_space_is_map(__isl_keep isl_space *space);
创建与其他对象位于同一空间的对象通常很有用。这可以通过基于原始对象的空间来创建新对象(请参见“创建新的集合和关系”或“函数”)来完成。
创建和一个多面体对象相同space的space:
#include <isl/polynomial.h>
isl_space *isl_qpolynomial_get_domain_space(isl_qpolynomial *qp);
isl_space *isl_qpolynomial_get_space(isl_qpolynomial *qp);
isl_space *isl_qpolynomial_fold_get_domain_space(
__isl_keep isl_qpolynomial_fold *fold);
__isl_give isl_space *isl_qpolynomial_fold_get_space(
__isl_keep isl_qpolynomial_fold *fold);
__isl_give isl_space *isl_pw_qpolynomial_get_domain_space(
__isl_keep isl_pw_qpolynomial *pwqp);
__isl_give isl_space *isl_pw_qpolynomial_get_space(
__isl_keep isl_pw_qpolynomial *pwqp);
__isl_give isl_space *isl_pw_qpolynomial_fold_get_domain_space(
__isl_keep isl_pw_qpolynomial_fold *pwf);
__isl_give isl_space *isl_pw_qpolynomial_fold_get_space(
__isl_keep isl_pw_qpolynomial_fold *pwf);
__isl_give isl_space *isl_union_pw_qpolynomial_get_space(
__isl_keep isl_union_pw_qpolynomial *upwqp);
__isl_give isl_space *isl_union_pw_qpolynomial_fold_get_space(
__isl_keep isl_union_pw_qpolynomial_fold *upwf);
可以使用以下功能将其他参数添加到空间。
#include <isl/space.h>
__isl_give isl_space *isl_space_add_param_id(
__isl_take isl_space *space,
__isl_take isl_id *id);
相反,可以使用以下函数从空格中删除所有参数。
#include <isl/space.h>
__isl_give isl_space *isl_space_drop_all_params(
__isl_take isl_space *space);
isl基本操作
-
1.create set & map
- Empty sets and relations
可以看出来。set和map的创建时凭借于space的。
__isl_give isl_basic_set *isl_basic_set_empty(
__isl_take isl_space *space);//创建一个空的set空间
__isl_give isl_basic_map *isl_basic_map_empty(
__isl_take isl_space *space);
__isl_give isl_set *isl_set_empty(
__isl_take isl_space *space);
__isl_give isl_map *isl_map_empty(
__isl_take isl_space *space);
__isl_give isl_union_set *isl_union_set_empty(
__isl_take isl_space *space);
__isl_give isl_union_map *isl_union_map_empty(
__isl_take isl_space *space);
** Universe sets and relations
_isl_give isl_basic_set *isl_basic_set_universe(
__isl_take isl_space *space);
__isl_give isl_basic_map *isl_basic_map_universe(
__isl_take isl_space *space);
__isl_give isl_set *isl_set_universe(
__isl_take isl_space *space);
__isl_give isl_map *isl_map_universe(
__isl_take isl_space *space);
__isl_give isl_union_set *isl_union_set_universe(
__isl_take isl_union_set *uset);
__isl_give isl_union_map *isl_union_map_universe(
__isl_take isl_union_map *umap);
** Identity relations
__isl_give isl_basic_map *isl_basic_map_identity(
__isl_take isl_space *space);
__isl_give isl_map *isl_map_identity(
__isl_take isl_space *space);
** 可以使用以下功能将基本集合或关系转换为集合或关系:
__isl_give isl_set *isl_set_from_basic_set(
__isl_take isl_basic_set *bset);
__isl_give isl_map *isl_map_from_basic_map(
__isl_take isl_basic_map *bmap);
** 例如,要创建一个包含10到42之间的偶数整数的集合,可以使用以下代码。
isl_space *space;
isl_local_space *ls;
isl_constraint *c;
isl_basic_set *bset;
space = isl_space_set_alloc(ctx, 0, 2);
bset = isl_basic_set_universe(isl_space_copy(space));
ls = isl_local_space_from_space(space);
c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1);
c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, 2);
bset = isl_basic_set_add_constraint(bset, c);
c = isl_constraint_alloc_inequality(isl_local_space_copy(ls));
c = isl_constraint_set_constant_si(c, -10);
c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1);
bset = isl_basic_set_add_constraint(bset, c);
c = isl_constraint_alloc_inequality(ls);
c = isl_constraint_set_constant_si(c, 42);
c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1);
bset = isl_basic_set_add_constraint(bset, c);
bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 1);
或者:
isl_basic_set *bset;
bset = isl_basic_set_read_from_str(ctx,
"{[i] : exists (a : i = 2a and i >= 10 and i <= 42)}");
整体程序如下:
int main()
{
isl_ctx *ctx = isl_ctx_alloc();
isl_basic_set *bset;
bset = isl_basic_set_read_from_str(ctx, "{[i] : exists (a : i = 2a and i >= 10 and i <= 42)}");
const char *out = isl_basic_set_to_str(bset);
cout << out << endl;
return 0;
}
最终输出:
{ [i] : (i) mod 2 = 0 and 10 <= i <= 42 }
这便是一个最简单的调度编写,这种语法表示 i 是一个循环变量,接下来我们看一下,如何能从字符串创建相应的 set、map 等对象。
2.Input & output
对于集合和关系,isl支持其自己的输入/输出格式,该格式类似于该Omega格式,但PolyLib在某些情况下还支持该格式。对于其他对象类型,通常仅isl支持一种格式。
输入
例如从输入格式创建一个basic_set对象:
#include <stdio.h>
#include <isl/ctx.h>
#include <isl/set.h>
using namespace std;
int main()
{
isl_ctx *ctx = isl_ctx_alloc();//create a ctx object
isl_basic_set *bset;
bset = isl_basic_set_read_from_str(ctx, "[n] -> { [i] : exists (a = [i/10] : 0 <= i and i <= n and i - 10 a <= 6) }");
//表示 i % 10 <= 6
char *out = isl_basic_set_to_str(bset);
printf("%s\n", out);
isl_basic_set_free(bset);
isl_ctx_free(ctx);
return 0;
}
输出结果:
n -> { [i] : 0 <= i <= n and 10*floor((3 + i)/10) <= i }
floor表示向下取整,可以看到isl帮我们把这样的循环变量进行了一些微调。
我们还可以使用以下的函数来从特定的输入格式创建相应对象:
#include <isl/id.h>
__isl_give isl_id *isl_id_read_from_str(isl_ctx *ctx,
const char *str);//创建id对象
__isl_give isl_multi_id *isl_multi_id_read_from_str(
isl_ctx *ctx, const char *str);
#include <isl/val.h>
__isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx,
const char *str);//创建一个val对象
__isl_give isl_multi_val *isl_multi_val_read_from_str(
isl_ctx *ctx, const char *str);
#include <isl/set.h>
__isl_give isl_basic_set *isl_basic_set_read_from_file(
isl_ctx *ctx, FILE *input);
__isl_give isl_basic_set *isl_basic_set_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_set *isl_set_read_from_file(isl_ctx *ctx,
FILE *input);
__isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx,
const char *str);
#include <isl/map.h>
__isl_give isl_basic_map *isl_basic_map_read_from_file(
isl_ctx *ctx, FILE *input);
__isl_give isl_basic_map *isl_basic_map_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_map *isl_map_read_from_file(
isl_ctx *ctx, FILE *input);
__isl_give isl_map *isl_map_read_from_str(isl_ctx *ctx,
const char *str);
#include <isl/union_set.h>
__isl_give isl_union_set *isl_union_set_read_from_file(
isl_ctx *ctx, FILE *input);
__isl_give isl_union_set *isl_union_set_read_from_str(
isl_ctx *ctx, const char *str);
#include <isl/union_map.h>
__isl_give isl_union_map *isl_union_map_read_from_file(
isl_ctx *ctx, FILE *input);
__isl_give isl_union_map *isl_union_map_read_from_str(
isl_ctx *ctx, const char *str);
#include <isl/aff.h>
__isl_give isl_aff *isl_aff_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_multi_aff *isl_multi_aff_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_pw_aff *isl_pw_aff_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_union_pw_aff *
isl_union_pw_aff_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_union_pw_multi_aff *
isl_union_pw_multi_aff_read_from_str(
isl_ctx *ctx, const char *str);
__isl_give isl_multi_union_pw_aff *
isl_multi_union_pw_aff_read_from_str(
isl_ctx *ctx, const char *str);
#include <isl/polynomial.h>
__isl_give isl_union_pw_qpolynomial *
isl_union_pw_qpolynomial_read_from_str(
isl_ctx *ctx, const char *str);
输出
在可以打印任何内容之前,需要先创建一个isl_printer对象:
__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx,
FILE *file);
__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx);
__isl_null isl_printer *isl_printer_free(
__isl_take isl_printer *printer);
isl_printer_to_file打印到给定的文件,同时isl_printer_to_str打印到可以使用以下函数提取的字符串。
#include <isl/printer.h>
__isl_give char *isl_printer_get_str(
__isl_keep isl_printer *printer);
还是刚才的程序,我们继续用isl_printer对象来输出:
int main()
{
isl_ctx *ctx = isl_ctx_alloc();//create a ctx object
isl_basic_set *bset;
bset = isl_basic_set_read_from_str(ctx, "[n] -> { [i] : exists (a = [i/10] : 0 <= i and i <= n and i - 10 a <= 6) }");
char *out = isl_basic_set_to_str(bset);
printf("%s\n", out);
isl_printer *p = isl_printer_to_str(ctx);
p = isl_printer_print_basic_set(p, bset); //表示输出basic_set
char *out2 = isl_printer_get_str(p);
printf("%s", out2);
isl_printer_free(p);
isl_basic_set_free(bset);
isl_ctx_free(ctx);
return 0;
}
输出结果为两行一样的循环变量约束:
n -> { [i] : 0 <= i <= n and 10floor((3 + i)/10) <= i }
n -> { [i] : 0 <= i <= n and 10floor((3 + i)/10) <= i }
另外,可以使用以下函数直接获取字符串表示形式,该函数始终以isl格式打印:
#include <isl/space.h>
__isl_give char *isl_space_to_str(
__isl_keep isl_space *space);
#include <isl/val.h>
__isl_give char *isl_val_to_str(__isl_keep isl_val *v);
__isl_give char *isl_multi_val_to_str(
__isl_keep isl_multi_val *mv);
#include <isl/set.h>
__isl_give char *isl_basic_set_to_str(
__isl_keep isl_basic_set *bset);
__isl_give char *isl_set_to_str(
__isl_keep isl_set *set);
#include <isl/union_set.h>
__isl_give char *isl_union_set_to_str(
__isl_keep isl_union_set *uset);
#include <isl/map.h>
__isl_give char *isl_basic_map_to_str(
__isl_keep isl_basic_map *bmap);
__isl_give char *isl_map_to_str(
__isl_keep isl_map *map);
#include <isl/union_map.h>
__isl_give char *isl_union_map_to_str(
__isl_keep isl_union_map *umap);