+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx,
+ FILE *input)
+{
+ isl_pw_qpolynomial *pwqp;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ pwqp = isl_stream_read_pw_qpolynomial(s);
+ isl_stream_free(s);
+ return pwqp;
+}
+
+/* Is the next token an identifer not in "v"?
+ */
+static int next_is_fresh_ident(struct isl_stream *s, struct vars *v)
+{
+ int n = v->n;
+ int fresh;
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ return 0;
+ fresh = tok->type == ISL_TOKEN_IDENT && vars_pos(v, tok->u.s, -1) >= n;
+ isl_stream_push_token(s, tok);
+
+ vars_drop(v, v->n - n);
+
+ return fresh;
+}
+
+/* First read the domain of the affine expression, which may be
+ * a parameter space or a set.
+ * The tricky part is that we don't know if the domain is a set or not,
+ * so when we are trying to read the domain, we may actually be reading
+ * the affine expression itself (defined on a parameter domains)
+ * If the tuple we are reading is named, we assume it's the domain.
+ * Also, if inside the tuple, the first thing we find is a nested tuple
+ * or a new identifier, we again assume it's the domain.
+ * Otherwise, we assume we are reading an affine expression.
+ */
+static __isl_give isl_set *read_aff_domain(struct isl_stream *s,
+ __isl_take isl_set *dom, struct vars *v)
+{
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (tok && (tok->type == ISL_TOKEN_IDENT || tok->is_keyword)) {
+ isl_stream_push_token(s, tok);
+ return read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+ }
+ if (!tok || tok->type != '[') {
+ isl_stream_error(s, tok, "expecting '['");
+ goto error;
+ }
+ if (next_is_tuple(s) || next_is_fresh_ident(s, v)) {
+ isl_stream_push_token(s, tok);
+ dom = read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+ } else
+ isl_stream_push_token(s, tok);
+
+ return dom;
+error:
+ if (tok)
+ isl_stream_push_token(s, tok);
+ isl_set_free(dom);
+ return NULL;
+}
+
+/* Read an affine expression from "s".
+ */
+__isl_give isl_aff *isl_stream_read_aff(struct isl_stream *s)
+{
+ isl_aff *aff;
+ isl_multi_aff *ma;
+
+ ma = isl_stream_read_multi_aff(s);
+ if (!ma)
+ return NULL;
+ if (isl_multi_aff_dim(ma, isl_dim_out) != 1)
+ isl_die(s->ctx, isl_error_invalid,
+ "expecting single affine expression",
+ goto error);
+
+ aff = isl_multi_aff_get_aff(ma, 0);
+ isl_multi_aff_free(ma);
+ return aff;
+error:
+ isl_multi_aff_free(ma);
+ return NULL;
+}
+
+/* Read a piecewise affine expression from "s" with domain (space) "dom".
+ */
+static __isl_give isl_pw_aff *read_pw_aff_with_dom(struct isl_stream *s,
+ __isl_take isl_set *dom, struct vars *v)
+{
+ isl_pw_aff *pwaff = NULL;
+
+ if (!isl_set_is_params(dom) && isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+
+ if (isl_stream_eat(s, '['))
+ goto error;
+
+ pwaff = accept_affine(s, isl_set_get_space(dom), v);
+
+ if (isl_stream_eat(s, ']'))
+ goto error;
+
+ dom = read_optional_disjuncts(s, dom, v, 0);
+ pwaff = isl_pw_aff_intersect_domain(pwaff, dom);
+
+ return pwaff;
+error:
+ isl_set_free(dom);
+ isl_pw_aff_free(pwaff);
+ return NULL;
+}
+
+__isl_give isl_pw_aff *isl_stream_read_pw_aff(struct isl_stream *s)
+{
+ struct vars *v;
+ isl_set *dom = NULL;
+ isl_set *aff_dom;
+ isl_pw_aff *pa = NULL;
+ int n;
+
+ v = vars_new(s->ctx);
+ if (!v)
+ return NULL;
+
+ dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+ if (next_is_tuple(s)) {
+ dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+ if (isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+ }
+ if (isl_stream_eat(s, '{'))
+ goto error;
+
+ n = v->n;
+ aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+ pa = read_pw_aff_with_dom(s, aff_dom, v);
+ vars_drop(v, v->n - n);
+
+ while (isl_stream_eat_if_available(s, ';')) {
+ isl_pw_aff *pa_i;
+
+ n = v->n;
+ aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+ pa_i = read_pw_aff_with_dom(s, aff_dom, v);
+ vars_drop(v, v->n - n);
+
+ pa = isl_pw_aff_union_add(pa, pa_i);
+ }
+
+ if (isl_stream_eat(s, '}'))
+ goto error;
+
+ vars_free(v);
+ isl_set_free(dom);
+ return pa;
+error:
+ vars_free(v);
+ isl_set_free(dom);
+ isl_pw_aff_free(pa);
+ return NULL;
+}
+
+__isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str)
+{
+ isl_aff *aff;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ aff = isl_stream_read_aff(s);
+ isl_stream_free(s);
+ return aff;
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str)
+{
+ isl_pw_aff *pa;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ pa = isl_stream_read_pw_aff(s);
+ isl_stream_free(s);
+ return pa;
+}
+
+/* Read an isl_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_pw_multi_aff.
+ * It would be more efficient if we were to construct the isl_pw_multi_aff
+ * directly.
+ */
+__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff(struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (!obj.v)
+ return NULL;
+
+ if (obj.type == isl_obj_map)
+ return isl_pw_multi_aff_from_map(obj.v);
+ if (obj.type == isl_obj_set)
+ return isl_pw_multi_aff_from_set(obj.v);
+
+ obj.type->free(obj.v);
+ isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+ return NULL);
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
+ const char *str)
+{
+ isl_pw_multi_aff *pma;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ pma = isl_stream_read_pw_multi_aff(s);
+ isl_stream_free(s);
+ return pma;
+}
+
+/* Read an isl_union_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_union_pw_multi_aff.
+ * It would be more efficient if we were to construct
+ * the isl_union_pw_multi_aff directly.
+ */
+__isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff(
+ struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (!obj.v)
+ return NULL;
+
+ if (obj.type == isl_obj_map || obj.type == isl_obj_set)
+ obj = to_union(s->ctx, obj);
+ if (obj.type == isl_obj_union_map)
+ return isl_union_pw_multi_aff_from_union_map(obj.v);
+ if (obj.type == isl_obj_union_set)
+ return isl_union_pw_multi_aff_from_union_set(obj.v);
+
+ obj.type->free(obj.v);
+ isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+ return NULL);
+}
+
+/* Read an isl_union_pw_multi_aff from "str".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
+ isl_ctx *ctx, const char *str)
+{
+ isl_union_pw_multi_aff *upma;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ upma = isl_stream_read_union_pw_multi_aff(s);
+ isl_stream_free(s);
+ return upma;
+}
+
+/* Assuming "pa" represents a single affine expression defined on a universe
+ * domain, extract this affine expression.
+ */
+static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa)
+{
+ isl_aff *aff;
+
+ if (!pa)
+ return NULL;
+ if (pa->n != 1)
+ isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+ "expecting single affine expression",
+ goto error);
+ if (!isl_set_plain_is_universe(pa->p[0].set))
+ isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+ "expecting universe domain",
+ goto error);
+
+ aff = isl_aff_copy(pa->p[0].aff);
+ isl_pw_aff_free(pa);
+ return aff;
+error:
+ isl_pw_aff_free(pa);
+ return NULL;
+}
+
+/* Read a multi-affine expression from "s".
+ * If the multi-affine expression has a domain, then then tuple
+ * representing this domain cannot involve any affine expressions.
+ * The tuple representing the actual expressions needs to consist
+ * of only affine expressions. Moreover, these expressions can
+ * only depend on parameters and input dimensions and not on other
+ * output dimensions.
+ */
+__isl_give isl_multi_aff *isl_stream_read_multi_aff(struct isl_stream *s)
+{
+ struct vars *v;
+ isl_set *dom = NULL;
+ isl_multi_pw_aff *tuple = NULL;
+ int dim, i, n;
+ isl_space *space, *dom_space;
+ isl_multi_aff *ma = NULL;
+
+ v = vars_new(s->ctx);
+ if (!v)
+ return NULL;
+
+ dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+ if (next_is_tuple(s)) {
+ dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+ if (isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+ }
+ if (!isl_set_plain_is_universe(dom))
+ isl_die(s->ctx, isl_error_invalid,
+ "expecting universe parameter domain", goto error);
+ if (isl_stream_eat(s, '{'))
+ goto error;
+
+ tuple = read_tuple(s, v, 0, 0);
+ if (!tuple)
+ goto error;
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
+ isl_set *set;
+ isl_space *space;
+ int has_expr;
+
+ has_expr = tuple_has_expr(tuple);
+ if (has_expr < 0)
+ goto error;
+ if (has_expr)
+ isl_die(s->ctx, isl_error_invalid,
+ "expecting universe domain", goto error);
+ space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+ set = isl_set_universe(space);
+ dom = isl_set_intersect_params(set, dom);
+ isl_multi_pw_aff_free(tuple);
+ tuple = read_tuple(s, v, 0, 0);
+ if (!tuple)
+ goto error;
+ }
+
+ if (isl_stream_eat(s, '}'))
+ goto error;
+
+ n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+ dim = isl_set_dim(dom, isl_dim_all);
+ dom_space = isl_set_get_space(dom);
+ space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+ space = isl_space_align_params(space, isl_space_copy(dom_space));
+ if (!isl_space_is_params(dom_space))
+ space = isl_space_map_from_domain_and_range(
+ isl_space_copy(dom_space), space);
+ isl_space_free(dom_space);
+ ma = isl_multi_aff_alloc(space);
+
+ for (i = 0; i < n; ++i) {
+ isl_pw_aff *pa;
+ isl_aff *aff;
+ pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+ aff = aff_from_pw_aff(pa);
+ if (!aff)
+ goto error;
+ if (isl_aff_involves_dims(aff, isl_dim_in, dim, i + 1)) {
+ isl_aff_free(aff);
+ isl_die(s->ctx, isl_error_invalid,
+ "not an affine expression", goto error);
+ }
+ aff = isl_aff_drop_dims(aff, isl_dim_in, dim, n);
+ space = isl_multi_aff_get_domain_space(ma);
+ aff = isl_aff_reset_domain_space(aff, space);
+ ma = isl_multi_aff_set_aff(ma, i, aff);
+ }
+
+ isl_multi_pw_aff_free(tuple);
+ vars_free(v);
+ isl_set_free(dom);
+ return ma;
+error:
+ isl_multi_pw_aff_free(tuple);
+ vars_free(v);
+ isl_set_free(dom);
+ isl_multi_aff_free(ma);
+ return NULL;
+}
+
+__isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx,
+ const char *str)
+{
+ isl_multi_aff *maff;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ maff = isl_stream_read_multi_aff(s);
+ isl_stream_free(s);
+ return maff;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial(
+ struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (obj.type == isl_obj_pw_qpolynomial) {
+ obj.type = isl_obj_union_pw_qpolynomial;
+ obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
+ }
+ if (obj.v)
+ isl_assert(s->ctx, obj.type == isl_obj_union_pw_qpolynomial,
+ goto error);
+
+ return obj.v;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str(
+ isl_ctx *ctx, const char *str)
+{
+ isl_union_pw_qpolynomial *upwqp;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ upwqp = isl_stream_read_union_pw_qpolynomial(s);
+ isl_stream_free(s);
+ return upwqp;
+}