Skip to content

Commit 3eefa8a

Browse files
committed
Add jet_poly example with total derivative
1 parent 40e69c2 commit 3eefa8a

File tree

2 files changed

+280
-0
lines changed

2 files changed

+280
-0
lines changed

dev/check_examples.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ then
206206
fi
207207
echo "PASS"
208208
exit 0
209+
elif test "$1" = "jet_poly";
210+
then
211+
echo "jet_poly.....SKIPPED"
209212
elif test "$1" = "keiper_li";
210213
then
211214
echo "keiper_li....SKIPPED"

examples/jet_poly.c

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
#include <flint/fmpq.h>
2+
#include <flint/fmpq_mpoly.h>
3+
#include <string.h>
4+
5+
typedef struct {
6+
slong base_nvars;
7+
slong fibre_nvars;
8+
slong max_diff_order;
9+
slong nvars;
10+
slong nvars_with_derivatives;
11+
const char** base_vars;
12+
const char** vars;
13+
slong* vars_derivatives;
14+
} jet_ctx_struct;
15+
16+
typedef jet_ctx_struct jet_ctx_t[1];
17+
18+
const char *jet_variable_from_multi_index(slong *multi_index, slong num_derivatives, slong base_nvars, const char **base_vars, const char *fibre_var) {
19+
/* TODO: Handle longer base and fibre variable names? */
20+
char* var = flint_malloc(sizeof(char) * (2 + num_derivatives + 1));
21+
var[0] = fibre_var[0];
22+
var[1] = '_';
23+
size_t idx = 2;
24+
for (slong i = 0; i < base_nvars; i++) {
25+
for (slong j = 0; j < multi_index[i]; j++) {
26+
var[idx++] = base_vars[i][0];
27+
}
28+
}
29+
var[idx] = '\0';
30+
return var;
31+
}
32+
33+
void jet_ctx_init(jet_ctx_t jctx, const char** base_vars, slong base_nvars, const char** fibre_vars, slong fibre_nvars, slong max_diff_order)
34+
{
35+
fmpz_t nvars, tmp, nvars_with_derivatives, num_multi_indices, num_multi_indices_prev, num_vars_prev;
36+
size_t pos, idx, local_offset;
37+
slong num_derivatives, fibre_idx, i, rem;
38+
slong *cur, *cur_integral, *jet_multi_indices, *jet_multi_indices_prev = NULL, *jet_multi_indices_prev_prev = NULL;
39+
40+
jctx->base_nvars = base_nvars;
41+
jctx->fibre_nvars = fibre_nvars;
42+
jctx->max_diff_order = max_diff_order;
43+
jctx->base_vars = base_vars; /* NOTE: Not copying */
44+
45+
/* Count the number of jet variables: u, v, u_x, u_y, u_z, u_xx, etc. */
46+
fmpz_init(nvars);
47+
fmpz_init(tmp);
48+
fmpz_zero(nvars);
49+
/* TODO: Binomial sum closed form? */
50+
for (slong i = 0; i <= max_diff_order; i++) {
51+
fmpz_bin_uiui(tmp, (ulong)(base_nvars + i - 1), (ulong)i);
52+
fmpz_add(nvars, nvars, tmp);
53+
}
54+
fmpz_mul_si(nvars, nvars, fibre_nvars);
55+
fmpz_set(nvars_with_derivatives, nvars);
56+
fmpz_submul_si(nvars_with_derivatives, tmp, fibre_nvars);
57+
fmpz_clear(tmp);
58+
59+
/* Generate jet variable names. */
60+
61+
jctx->nvars = fmpz_get_ui(nvars);
62+
jctx->nvars_with_derivatives = fmpz_get_si(nvars_with_derivatives);
63+
jctx->vars = flint_malloc(sizeof(char*) * (size_t) fmpz_get_ui(nvars));
64+
jctx->vars_derivatives = flint_malloc(sizeof(slong) * (size_t) (base_nvars * jctx->nvars_with_derivatives));
65+
66+
/*
67+
* Generating integer vectors, based on SageMath's integer_vectors_nk_fast_iter
68+
* https://github.com/sagemath/sage/blob/931cc5e8dc03580c9fecbd0535544a725e9baeb7/src/sage/combinat/integer_vector.py#L1742
69+
*/
70+
idx = 0;
71+
cur = flint_malloc(sizeof(slong) * base_nvars);
72+
cur_integral = flint_malloc(sizeof(slong) * base_nvars);
73+
jet_multi_indices = flint_calloc(base_nvars, sizeof(slong)); /* NOTE: Multi-indices with all zero entries. */
74+
fmpz_init(num_multi_indices);
75+
fmpz_init(num_multi_indices_prev);
76+
fmpz_init(num_vars_prev);
77+
fmpz_one(num_multi_indices);
78+
fmpz_zero(num_vars_prev);
79+
for (i = 0; i < fibre_nvars; i++) {
80+
/* TODO: Support longer fibre variable lengths? */
81+
jctx->vars[idx] = flint_malloc(sizeof(char));
82+
strncpy((char*)jctx->vars[idx], fibre_vars[i], 1);
83+
idx++;
84+
}
85+
for (num_derivatives = 1; num_derivatives <= max_diff_order; num_derivatives++) {
86+
jet_multi_indices_prev_prev = jet_multi_indices_prev;
87+
if (jet_multi_indices_prev_prev != NULL) flint_free(jet_multi_indices_prev_prev);
88+
jet_multi_indices_prev = jet_multi_indices;
89+
fmpz_addmul_si(num_vars_prev, num_multi_indices_prev, fibre_nvars);
90+
fmpz_set(num_multi_indices_prev, num_multi_indices);
91+
fmpz_bin_uiui(num_multi_indices, (ulong)(base_nvars + num_derivatives - 1), (ulong)num_derivatives);
92+
jet_multi_indices = flint_malloc(sizeof(slong) * fibre_nvars * (size_t)fmpz_get_ui(num_multi_indices));
93+
local_offset = 0;
94+
for (fibre_idx = 0; fibre_idx < fibre_nvars; fibre_idx++) {
95+
/* Integer vectors of length nvars that sum to num_derivatives */
96+
cur[0] = num_derivatives + 1; /* NOTE: Artificial + 1 to make the loop work. */
97+
for (i = 1; i < base_nvars; i++) {
98+
cur[i] = 0;
99+
}
100+
101+
pos = 0;
102+
rem = -1; /* NOTE: Artificial -1 to make the loop work. */
103+
while (1) {
104+
if (cur[pos] == 0) {
105+
if (pos == 0) {
106+
break;
107+
} else {
108+
pos--;
109+
continue;
110+
}
111+
}
112+
cur[pos]--;
113+
rem++;
114+
115+
int rollover = (pos + 2 == (size_t) base_nvars);
116+
if (rollover) {
117+
cur[pos + 1] = rem;
118+
} else {
119+
pos++;
120+
cur[pos] = rem; /* Guaranteed to be at least 1. */
121+
}
122+
123+
/* Store the multi-index (for simplicity, only do it for the total derivatives of the first fibre variable) */
124+
if (fibre_idx == 0) {
125+
memcpy(jet_multi_indices + local_offset, cur, sizeof(slong) * base_nvars);
126+
local_offset += base_nvars;
127+
}
128+
129+
jctx->vars[idx] = jet_variable_from_multi_index(cur, num_derivatives, base_nvars, base_vars, fibre_vars[fibre_idx]);
130+
131+
/* Find all the "integrals" of the jet variable, if any */
132+
memcpy(cur_integral, cur, sizeof(slong) * base_nvars);
133+
for (i = 0; i < base_nvars; i++) {
134+
if (cur[i] == 0)
135+
continue;
136+
int found = 0;
137+
cur_integral[i]--;
138+
for (size_t j = 0; j < (size_t)fmpz_get_ui(num_multi_indices_prev); j++) {
139+
if (memcmp(jet_multi_indices_prev + j*base_nvars, cur_integral, sizeof(slong) * base_nvars) == 0) {
140+
/* Store the derivative */
141+
size_t j_global = fmpz_get_ui(num_vars_prev) + fibre_idx * fmpz_get_ui(num_multi_indices_prev) + j;
142+
jctx->vars_derivatives[i * jctx->nvars_with_derivatives + j_global] = idx;
143+
found = 1;
144+
break;
145+
}
146+
}
147+
(void)found; /* Silence compiler warning when asserts are disabled. */
148+
FLINT_ASSERT(found);
149+
cur_integral[i]++;
150+
}
151+
152+
idx++;
153+
154+
if (rollover) {
155+
cur[pos + 1] = 0;
156+
} else {
157+
rem = 0;
158+
}
159+
}
160+
}
161+
}
162+
flint_free(cur);
163+
flint_free(cur_integral);
164+
flint_free(jet_multi_indices);
165+
flint_free(jet_multi_indices_prev);
166+
fmpz_clear(num_multi_indices);
167+
fmpz_clear(num_multi_indices_prev);
168+
169+
fmpz_clear(nvars);
170+
}
171+
172+
void jet_ctx_clear(jet_ctx_t jctx)
173+
{
174+
for (slong i = 0; i < jctx->nvars; i++) {
175+
flint_free((void*)jctx->vars[i]);
176+
}
177+
flint_free(jctx->vars);
178+
flint_free(jctx->vars_derivatives);
179+
}
180+
181+
void _fmpq_mpoly_jet_total_derivative(fmpq_mpoly_t res, const fmpq_mpoly_t f, slong base_var, fmpq_mpoly_ctx_t ctx, jet_ctx_t jctx)
182+
{
183+
fmpq_mpoly_zero(res, ctx);
184+
fmpq_mpoly_t tmp;
185+
fmpq_mpoly_init(tmp, ctx);
186+
fmpq_mpoly_t v;
187+
fmpq_mpoly_init(v, ctx);
188+
for (slong i = 0; i < jctx->nvars_with_derivatives; i++)
189+
{
190+
fmpq_mpoly_derivative(tmp, f, i, ctx);
191+
if (!fmpq_mpoly_is_zero(tmp, ctx))
192+
{
193+
fmpq_mpoly_gen(v, jctx->vars_derivatives[base_var * jctx->nvars_with_derivatives + i], ctx);
194+
fmpq_mpoly_mul(tmp, tmp, v, ctx);
195+
fmpq_mpoly_add(res, res, tmp, ctx);
196+
}
197+
}
198+
fmpq_mpoly_clear(tmp, ctx);
199+
fmpq_mpoly_clear(v, ctx);
200+
}
201+
202+
void fmpq_mpoly_jet_total_derivative(fmpq_mpoly_t res, const fmpq_mpoly_t f, slong base_var, fmpq_mpoly_ctx_t ctx, jet_ctx_t jctx)
203+
{
204+
if (res == f)
205+
{
206+
fmpq_mpoly_t tmp;
207+
fmpq_mpoly_init(tmp, ctx);
208+
_fmpq_mpoly_jet_total_derivative(tmp, f, base_var, ctx, jctx);
209+
fmpq_mpoly_swap(tmp, res, ctx);
210+
fmpq_mpoly_clear(tmp, ctx);
211+
}
212+
else
213+
{
214+
_fmpq_mpoly_jet_total_derivative(res, f, base_var, ctx, jctx);
215+
}
216+
}
217+
218+
void print_total_derivative(const fmpq_mpoly_t f, slong base_var, fmpq_mpoly_ctx_t ctx, jet_ctx_t jctx)
219+
{
220+
fmpq_mpoly_t df;
221+
fmpq_mpoly_init(df, ctx);
222+
flint_printf("d/d%s(", jctx->base_vars[base_var]);
223+
fmpq_mpoly_print_pretty(f, jctx->vars, ctx);
224+
flint_printf(") = ");
225+
fmpq_mpoly_jet_total_derivative(df, f, base_var, ctx, jctx);
226+
fmpq_mpoly_print_pretty(df, jctx->vars, ctx);
227+
fmpq_mpoly_clear(df, ctx);
228+
}
229+
230+
int main(int argc, char* argv[])
231+
{
232+
slong base_nvars = 3;
233+
slong fibre_nvars = 2;
234+
const char* base_vars[] = {"x", "y", "z"};
235+
const char* fibre_vars[] = {"u", "v"};
236+
slong max_diff_order = 3;
237+
238+
ordering_t ord = ORD_DEGREVLEX;
239+
fmpq_mpoly_ctx_t ctx;
240+
jet_ctx_t jctx;
241+
fmpq_mpoly_t v, f;
242+
243+
jet_ctx_init(jctx, base_vars, base_nvars, fibre_vars, fibre_nvars, max_diff_order);
244+
245+
fmpq_mpoly_ctx_init(ctx, jctx->nvars, ord);
246+
fmpq_mpoly_init(v, ctx);
247+
fmpq_mpoly_init(f, ctx);
248+
249+
for (slong base_var = 0; base_var < jctx->base_nvars; base_var++)
250+
{
251+
for (slong jet_var = 0; jet_var < jctx->nvars_with_derivatives; jet_var++) {
252+
fmpq_mpoly_gen(v, jet_var, ctx);
253+
print_total_derivative(v, base_var, ctx, jctx); flint_printf("; ");
254+
}
255+
flint_printf("\n");
256+
}
257+
flint_printf("\n");
258+
259+
fmpq_mpoly_set_str_pretty(f, "u^2", jctx->vars, ctx);
260+
print_total_derivative(f, 0, ctx, jctx); flint_printf("\n");
261+
fmpq_mpoly_set_str_pretty(f, "u^3", jctx->vars, ctx);
262+
print_total_derivative(f, 1, ctx, jctx); flint_printf("\n");
263+
fmpq_mpoly_set_str_pretty(f, "u*v", jctx->vars, ctx);
264+
print_total_derivative(f, 2, ctx, jctx); flint_printf("\n");
265+
fmpq_mpoly_set_str_pretty(f, "u_x*v_y", jctx->vars, ctx);
266+
print_total_derivative(f, 2, ctx, jctx); flint_printf("\n");
267+
268+
fmpq_mpoly_clear(v, ctx);
269+
fmpq_mpoly_clear(f, ctx);
270+
fmpq_mpoly_ctx_clear(ctx);
271+
272+
jet_ctx_clear(jctx);
273+
274+
flint_cleanup_master();
275+
276+
return 0;
277+
}

0 commit comments

Comments
 (0)