Question

In tcl I need to execute a script for each possible combination of values of an unknown number of variables.

Describing it in words:

A goes from a0 -> a1 with steps of "da"

B goes from b0 -> b1 with steps of "db"

C goes from c0 -> c1 with steps of "dc"

....

The number of variables can vary. Note: The names of the variables are not known beforehand, 'A' could also be called 'Ape' or anything else. Same goes for the other variables.

What I have so far is:

array set min_vals {A $a0 B $b0 C $c0 ...} ;# --> These are user-defined
array set max_vals {A $a1 B $b1 C $c1 ...} ;# --> These are user-defined
array set step_vals {A $da B $db C $dc ...} ;# --> These are user-defined

# First I determine the number of variables and the number of values they can have
set nr_vars [array size min_vals] ;# Determine nr of variables
set nr_vals [list] ;# --> Set empty list for nr of values for each variable

foreach var_name [array names min_vals] {
    set nr [expr {round( ( $max_vals(${var_name})-$min_vals(${var_name}) ) / $step_vals(${var_names}) )}]
    set nr_vals [concat $nr_vals $nr]
}

Now I need to somehow loop through each possible combination:

[A=a0, B=b0, C=c0]
[A=a0+da, B=b0, C=c0]
[A=a0+2*da, B=b0, C=c0]
...
...
[A=a1, B=b0, C=c0]
[A=a0, B=b0+db, C=c0]
[A=a0+da, B=b0+db, C=c0]
...
...
[A=a1, B=b1, C=c1]

I hope there is an easy way to do this. The only way I could think of doing this was by having a single loop with number of iterations containing all combinations and let each iteration-number correspond to a specific combination. But I'm sure there must be a less cumbersome way.

_

Edit:

Maybe I wasn't really clear about what I exactly wanted. I don't care about the actual output. My aim is to set each variable to the correct value and run another script with these variables:

set A $a0
set B $b0
set C $c0
source run/some/script.tcl

And repeat this for each possible combination of values of A, B and C.

Was it helpful?

Solution

Use nested for loops

for {set a $min_vals(A)} {$a <= $max_vals(A)} {incr a $step_vals(A)} {
    for {set b $min_vals(B)} {$b <= $max_vals(B)} {incr b $step_vals(B)} {
        for {set c $min_vals(C)} {$c <= $max_vals(C)} {incr c $step_vals(C)} {

            do something with [list $a $b $c]

        }
    }
}

Ah, needs to be more dynamic. Hmmm,

set variables {A B C}
array set min_vals  {A 1 B 10 C 100}
array set max_vals  {A 3 B 30 C 300}
array set step_vals {A 1 B 10 C 100}

proc build_loops {} {
    global variables 

    # create the "seed" code: what to do with the generated tuple
    set code "do_something_with \[list "
    foreach var $variables { 
        append code "\$[loop_var $var] " 
    }
    append code "]"

    # and wrap layers of for loops around the seed
    foreach var [lreverse $variables] {
        set loop_var [loop_var $var]
        set code [format {for {set %s $min_vals(%s)} {$%s <= $max_vals(%s)} {incr %s $step_vals(%s)} {%s}} \
            $loop_var $var \
            $loop_var $var \
            $loop_var $var \
            $code \
        ]
    }

    return $code
}

proc loop_var {varname} {
    return "loop_[string tolower $varname]"
}

proc do_something_with {args} {
    puts $args
}

set code [build_loops]
puts $code
eval $code
for {set loop_a $min_vals(A)} {$loop_a <= $max_vals(A)} {incr loop_a $step_vals(A)} {for {set loop_b $min_vals(B)} {$loop_b <= $max_vals(B)} {incr loop_b $step_vals(B)} {for {set loop_c $min_vals(C)} {$loop_c <= $max_vals(C)} {incr loop_c $step_vals(C)} {do_something_with [list $loop_a $loop_b $loop_c ]}}}
{1 10 100}
{1 10 200}
{1 10 300}
{1 20 100}
{1 20 200}
{1 20 300}
{1 30 100}
{1 30 200}
{1 30 300}
{2 10 100}
{2 10 200}
{2 10 300}
{2 20 100}
{2 20 200}
{2 20 300}
{2 30 100}
{2 30 200}
{2 30 300}
{3 10 100}
{3 10 200}
{3 10 300}
{3 20 100}
{3 20 200}
{3 20 300}
{3 30 100}
{3 30 200}
{3 30 300}

I keep a separate list of the variable names: [array names a] returns an unordered list of names, and (I assume) it is important to know the order of the tuple given to the do_something_with proc

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top