gmic
gmic copied to clipboard
Nested expression processing with vectors
It would seem that there's a bug with processing nested expression involving vectors.
Here's a sample code (I don't think I can come up with a smaller form at the moment). However, you'd have to look below and ignore the code that you're not supposed to look at when testing, and that small part is what I want you to focus on to see the bug.
rep_lavander_binary_map:
skip ${1=8}
check "$1>0&&($1==int($1))"
repeat $1 {
k={$>+1}
+rep_ncr_combinations $1,$k
{w},1,1,1,$k
rv[-2,-1]
a[-2,-1] c
}
local[-$1--1] {
total_length={sum(expr('w#x',$!))}
max_spectrum_count=${-max_s}
$total_length,1,1,$max_spectrum_count
p=0
repeat $1 {
j[-1] [$>],$p
p+={w#$>}
}
keep[-1]
}
local[-1] {
square_size={w#-1}
$square_size,$square_size,1,1,:"begin(
const max_index=$1;
p(pos)=I(#-1,pos,0,0);
empty_set=vector(#s#-1,0);
cp=[166,64];
and_set(v0,v1)=(
new_set=empty_set;
ins_to_new_set=1;
if(x==cp[0]&&y==cp[1],print(v0);print(v1););
repeat(v0[0],v0_ip,
v0_p=v0_ip+1;
repeat(v1[0],v1_ip,
v1_p=v1_ip+1;
if(v0[v0_p]==v1[v1_p],
new_set[ins_to_new_set]=v0[v0_p];
++new_set[0];
++ins_to_new_set;
);
);
);
if(x==cp[0]&&y==cp[1],print(new_set););
new_set;
);
or_set(v0,v1)=(
new_set=empty_set-1;
new_set[0]=0;
ins_to_new_set=1;
if(x==cp[0]&&y==cp[1],print(v0);print(v1););
repeat(v0[0],v0_ip,
v0_p=v0_ip+1;
v=v0[v0_p];
search_result=find(new_set,v,1,1);
if(search_result==-1,
new_set[ins_to_new_set]=v;
++new_set[0];
++ins_to_new_set;
);
);
repeat(v1[0],v1_ip,
v1_p=v1_ip+1;
v=v1[v1_p];
search_result=find(new_set,v,1,1);
if(search_result==-1,
new_set[ins_to_new_set]=v;
++new_set[0];
++ins_to_new_set;
);
);
if(x==cp[0]&&y==cp[1],print(new_set));
new_set;
);
diff_set(v0,v1)=(
new_set=empty_set;
ins_to_new_set=1;
if(x==cp[0]&&y==cp[1],print(v0);print(v1););
repeat(v0[0],v0_ip,
v0_p=v0_ip+1;
v=v0[v0_p];
found=0;
repeat(v1[0],v1_ip,
v1_p=v1[v1_ip+1];
if(v==v1_p,
found=1;
break();
);
);
if(!found,
new_set[ins_to_new_set]=v;
++new_set[0];
++ins_to_new_set;
);
);
if(x==cp[0]&&y==cp[1],print(new_set));
new_set;
);
xor_set(v0,v1)=(
new_set=empty_set;
ins_to_new_set=1;
if(x==cp[0]&&y==cp[1],print(v0);print(v1););
repeat(v1[0],v1_ip,
v1_p=v1_ip+1;
v=v1[v1_p];
found=0;
repeat(v0[0],v0_ip,
v0_p=v0[v0_ip+1];
if(v==v0_p,
found=1;
break();
);
);
if(!found,
new_set[ins_to_new_set]=v;
++new_set[0];
++ins_to_new_set;
);
);
repeat(v0[0],v0_ip,
v0_p=v0_ip+1;
v=v0[v0_p];
found=0;
repeat(v1[0],v1_ip,
v1_p=v1[v1_ip+1];
if(v==v1_p,
found=1;
break();
);
);
if(!found,
new_set[ins_to_new_set]=v;
++new_set[0];
++ins_to_new_set;
);
);
if(x==cp[0]&&y==cp[1],print(new_set));
new_set;
);
);
out=xor_set(p(x),p(y));
out=and_set(p(y),out);
out[0];"
}
rm..
Now, this gives the expected result after running $ rep_lavander_binary_map
.
Replace this part
out=xor_set(p(x),p(y));
out=diff_set(p(y),out);
With this:
out=diff_set( p(y), xor_set(p(x),p(y)) );
As you can see, it's virtually the same, but what happens after you run it?
The output turns out to be different. It is the first one that is correct.
There seem to be a issue with processing here.
out=diff_set( p(y), xor_set(p(x),p(y)) );
As you can see, it's virtually the same, but what happens after you run it?
No it's not. Do not forget that your diff_set()
is a macro, not a function. This makes a huge difference.
In your case, this means that your argument v1
in the macro diff_set()
will be replaced each time it is encountered in the macro code by the expression xor_set(p(x),p(y))
, which is probably (definitely) not what you want.
In particular, xor_set(p(x),p(y))
will be "called" multiple times here (each time you use v1
in your macro code).
If diff_set()
was a function, then xor_set()
would be called only once, when the function is called.
What would be the workaround to this issue? I'm thinking of making a command which basically would generate codes to get around this issue, and I know that's tough to do.
One idea I can think of is a new feature using character '@', this character should be put next to macros to have the JIT compiler assume it's a function or at least force it to call inner function only once. But, I don't know if this is feasible.
However, when writing after the macro function, the '@' can be omitted.
It's not planed to add functions (rather than macros) in math parser. This would mean: having to manage a stack for arguments push/pop, as well as a stack for keeping the current scope during the evaluation of the expression. It would complexify the parser for an usage where workarounds can be often found. Please don't use the math evaluator if you really need function calls. Use a "regular" G'MIC pipeline instead.