Multi-variable assignment/update

weird
scripting
gmic

(David Tschumperlé) #1

Yesterday, I’ve worked hard on the next release 2.0.1 of G’MIC, and added a quite useful feature I’d like to detail a little bit. It could be named “Multi-variable management”, and will be available in upcoming version 2.0.1.

  • In a G’MIC pipeline, you had the possibility to define a variable, like var=foo, and use its value afterwards with $var.
  • When the variable contained a numerical value, like var=3.1415926, you could even invoke arithmetic update operators to update its value, e.g. var*=2, equivalent to var={$var*2}.

The novelty in 2.0.1 comes from the fact that multiple variables can now be assigned/updated with a single line:

  • Multi-variable assignment: Expression

      A,B,C=0
    

becomes equivalent to

A=0 
B=0
C=0

Also

A,B,C=john,mike,kevin

can be used instead of

A=john
B=mike
C=kevin
  • That is actually pretty useful when you want a mathematical expression to return several values to be stored in different variables, as in

      min,max={img,[im,iM]}
    

to get both the min and max values of an image [img]. Indeed, before that, you had to write:

min={im}
max={iM}

but in that case, the interpreter had to loop over the image twice (one time to get the min, and the other time to get the max), which was not efficient.
The following trick was a way to avoid that:

minmax={img,[im,iM]}
min={arg(1,$minmax)} 
max={arg(2,$minmax)}

but this trick was a bit ugly and a pain to write.

  • Multi-variable update: But wait, similar expressions are now allowed to update variables containing numerical values as well ! So, for instance,

      A,B,C=2 
      A,B,C*=2,4,8
    

will result in A=4, B=8 and C=16.

  • Concatenation operator: A new string concatenation operator also appears, allowing to write things like this:

      S="David "
      S.="Tschumperle"
    

instead of

    S="David "
    S=${S}"Tschumperle"

and its multi-variable version also works, for instance:

foo:
  S1,S2,S3="Hello,","My name is ","David"
  -echo ${S1}${S2}${S3}
  S1,S2,S3.="\n"
  -echo ${S1}${S2}${S3}

will display:

$ gmic -foo
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./foo/ Set multiple variables 'S1=Hello,', 'S2=My name is ', 'S3=David'.
[gmic]-0./foo/ Hello,My name is David
[gmic]-0./foo/ Update multiple variables 'S1.=\n'->'Hello,\n', 'S2.=\n'->'My name is \n', 'S3.=\n'->'David\n'.
[gmic]-0./foo/ Hello,
My name is 
David

[gmic]-0./ End G'MIC interpreter.

A final word about this feature: empty variable values are allowed, so

A,B,C=,"I'm B",

will be equivalent to

A=
B="I'm B"
C=

If there are more than a single variable value provided, then there must be exactly as many values as the number of specified variable names, otherwise the item is not considered to be a variable assignment item:

$ gmic A,B,C=1
[gmic]-0./ Set multiple variables 'A=1', 'B=1', 'C=1'.

$ gmic A,B,C=1,2,3
[gmic]-0./ Set multiple variables 'A=1', 'B=2', 'C=3'.

$ gmic A,B,C=1,2
[gmic]-0./ Input file 'A' at position 0
[gmic]-0./ *** Error *** Command '-input': File 'A', format does not take any input options (options 'B,C=1,2' specified).

I’m sure there are many funny (and tricky!) uses of this new supported syntax, like this one:

foo :
  51,1,1,1,"x%2?',':'A'+x/2" 26,1,1,1,"round(u(0,100))"
  {/{-2,t}}={^}
  -rm[-2,-1]

which assigns a random integer value between 0 and 100 to all 26 variables that are the capital letters of the alphabet.

$ gmic -foo
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./foo/ Input image at position 0, with values 'x%2?',':'A'+x/2' (1 image 51x1x1x1).
[gmic]-1./foo/ Input image at position 1, with values 'round(u(0,100))' (1 image 26x1x1x1).
[gmic]-2./foo/ Set multiple variables 'A=69', 'B=90', 'C=17', 'D=50', 'E=61'(...)'V=5', 'W=76', 'X=25', 'Y=78', 'Z=55'.
[gmic]-2./foo/ Remove images [0,1] (0 images left).
[gmic]-0./ End G'MIC interpreter.

Yes, it’s probably a bit useless in this case, but still fun :slight_smile:
That’s all for now. You should be able to test this feature soon, as I’ve started posting new 2.0.1pre binaries on the G’MIC website.


#2

Interesting that the image statistics such as min/max are calculated each time, it’s not immediately obvious whether they’re calculated and stored until a change happens. Especially when it’s such a fast operation.

Abandon all readability :wink: but brevity is the G’MIC way so it’s fine by me!


(Pat David) #3

:smiley:


(David Tschumperlé) #4

Found another (very) useful case :

When you implement a new filter for GIMP, you can now name the parameters with one line, instead of using $1,$2,.. in your code :

#@gui My filter : my_filter,my_filter
#@gui : Smoothness = float(0,0,100)
#@gui : Normalize = bool(0)
my_filter : 
   smoothness,normalize=$"*"
   -b $smoothness
   -if $normalize -normalize 0,255 -endif

And now, if after all you want to insert a new text parameter between Smoothness and Normalize, you just have to write :

#@gui My filter : my_filter,my_filter
#@gui : Smoothness = float(0,0,100)
#@gui : Label = text("My awesome label")
#@gui : Normalize = bool(0)
my_filter : 
   smoothness,label,normalize=$"*"
   -b $smoothness
   -if $normalize -normalize 0,255 -endif
   -text_outline $label

and you won’t have to worry anymore about the fact that the old $2 has become $3, and so on, so no need to update all the code of your filter anymore each time you add a new parameter.
That is really cool ! :stuck_out_tongue:


(Lyle Kroll) #5

Look forward to seeing what iterative algorithms (my meaning is functions that call itself and update values and then call itself again) that this will be used for. Should make for rendering such things very fast possibly. :slight_smile: