How to assign value to a matrix in an indicator constraint

Is it possible and how to assign values to POSITION[R,C] matrix in the indicator constraint


    @variable(premex, ROLNA[R in keys(_ROWS), C in keys(_COLS), i_k in keys(_IMAGES_ALL)], Bin)
    @variable(premex, POSITION[R in keys(_ROWS), C in keys(_COLS)], Bin)
    @constraint(
      premex,
      SOMETHING[R in _ROWS, C in _COLS, i_k in keys(_IMAGES_ALL)],
      ROLNA[R, C, i_k]  => {
        POSITION[R1 + R - 1, C1 + C - 1]
        # for R1 in collect(UnitRange(1, _IMAGES_ALL[i_k]["ROWS"])), C1 in collect(UnitRange(1, _IMAGES_ALL[i_k]["COLS"])) 
          # if (R1 + R - 1 <= length(_ROWS)) 
            # for C1 in collect(UnitRange(1, _IMAGES_ALL[i_k]["COLS"])) 
              # if  (C1 + C - 1 <= length(_ROWS))
        == 1
      }
    )

My goal is to assign 1 to some values in POSITION matrix when ROLNA[R, C, i_k] = 1

What are these objects? Are ROLNA and POSITION both arrays of Variables?

I’ve updated my question by adding their definitions.

So it looks like they’re both arrays of binary variables. In that case, at the index of interest, can you simply say p == 1 and r == 1?

Also, I think it is better to omit the constraint name entirely than to name it something like dsadasd… unless that actually means something. I hope it isn’t rude to suggest there could be improvement to readability here :stuck_out_tongue_winking_eye:

Ok let me write this in C#

      int[] _ROWS = new int[10];
      int[] _COLS = new int[10];
      int[] _IMAGES = new int[10];
      int[,] POSITION = new int[10, 10];
      int[,,] ROLNA = new int[10, 10, 10];

      int R, C, i_k, R1, C1;

      for (R = 0; R < _ROWS.Length; R++)
      {
        for (C = 0; C < _COLS.Length; C++)
        {
          for (i_k = 0; i_k < _IMAGES.Length; i_k++)
          {
            if (ROLNA[R,C,i_k] == 1)
            {
              for (R1 = 0; R1 < 4; R1++)
              {
                for (C1 = 0; C1 < 4; C1++)
                {
                  if (R1 + R - 1 <= _ROWS.Length && C1 + C - 1 <= _COLS.Length)
                    POSITION[R1 + R - 1,C1 + C - 1] = 1;
                }
              }
            }
          }
        }
      }

So, iterate through all ROLNA and if one point is == 1 then assign 1 (ones) to a square in the POSITION matrix that way that upper left point matches the coordinates and add 4 x 4 to the right and down from that point - but really I don;t care this coordinates calculation, I need someone to help me how to assign values to a multidimensional array in indicator constraint and that is it, nothing more .

How to write this in Julia / Jump indicator constraint?

Is this an accurate translation?

for cartesian_index in eachindex(ROLNA)
    r, c, i = Tuple(cartesian_index)
    if value(ROLNA[r, c, i]) == 1
        @constraint(premex, [r1 = 0:3, c1 = 0:3], POSITION[r+r1, c+c1] == 1)
    end
end

Even if not, the point is you can write all of the logic outside the @constraint macro and do the @constraint in the same place you seem to be doing it in the C# code. (I did a bit of a hybrid; one of the loops is external and the other is internal, but they can both be internal or both be external and that works too.)


edit: with both loops external and accounting for the bounds, it now looks like this

for cartesian_index in eachindex(ROLNA)
    r, c, i = Tuple(cartesian_index)
    if value(ROLNA[r, c, i]) == 1
        for r′ in r:min(r+3, size(ROLNA, 1)),
            c′ in c:min(c+3, size(ROLNA, 2))

            @constraint(premex, POSITION[r′, c′] == 1)
        end
    end
end

It’s a bit suspicious though that we’re iterating over the last index (i, above) and not using it anywhere. If for each (r, c), if any i leads to a 1 constraint the rest don’t matter anymore, you could iterate on each coordinate (R, C, I) in a separate loop (like your C# code) and break the i loop if you encounter a 1 after setting the constraint. Could save you a tiny bit of repeated constraint setting :man_shrugging:. You could also use this to inform the loops on r, and c, since they should skip in increments of 4 in those cases… too complicated for me right now.

1 Like

Thanks, @tomerarnon that is exactly what I’ve needed → so it is quite possible to iterate and then add it to the @constraint macro. Great! I will try this now.

Indeed it is! That is my preferred method, personally.

Thanks for your assistance, you’ve opened just another gate for me so I can move on :smile:

1 Like

This advice is incorrect, because it will be based on the previously solved value of ROLNA.

Since both are binary, use

for r′ in r:min(r+3, size(ROLNA, 1))
    for c′ in c:min(c+3, size(ROLNA, 2))
        @constraint(premex, POSITION[r′, c′] >= ROLNA[r, c, i])
    end
end
1 Like

I assumed this was the intention. The fact that the constraint was described as an “indicator” should have suggested that was not so, but I didn’t think through that.

1 Like

No worries. It’s useful to see different examples of more advanced things you can do with JuMP (adding constraints conditionally in a loop based on a previous solution).

I’ve tried what have @tomerarnon advised but I didn’t get the correct results. Let me explain what I am trying to do here. I want to allow ROLNA to hold only the top-left coordinate of an image from a set of images. Then I would assign all 1 to the remaining points of that image to POSITION matrix, So if POSITION has a value on x,y ROLNA cannot. How to write that.

Here is what I’ve tried from the last suggestion:

    @timeit to "02. this should put ones to POSITION matrix" begin
      for R in _ROWS, C in _COLS, i_k in keys(_IMAGES_ALL)
        if ROLNA[R, C, i_k] == 1
          for R1 in collect(UnitRange(1, _IMAGES_ALL[i_k]["ROWS"])),
            C1 in collect(UnitRange(1, _IMAGES_ALL[i_k]["COLS"])) 
            if (R1 == 1 && C1 == 1)
              @constraint(premex, ROLNA[R, C, i_k] => {POSITION[R, C] == 0})
            elseif (R1 + R - 1 <= length(_ROWS)) && (C1 + C - 1 <= length(_COLS))
              @constraint(premex, ROLNA[R, C, i_k] => {POSITION[R1 + R - 1, C1 + C - 1] == 1})
            end            
          end            
        end
      end
    end

    @timeit to "03.this will prohibit ROLNA to take place that POSITION already holds" begin
      for i_k in keys(_IMAGES_ALL)
        @constraint(
          premex,
          [R in _ROWS, C in _COLS],
          POSITION[R, C] => {ROLNA[R, C, i_k] == 0}
        )
      end
    end

I think the way to do this is:

1 - POSITION[R, C] >= ROLNA[R, C, I_k]

so when p == 1 you get 0 >= r (ROLNA is 0), and when p == 0, 1 >= r, which does nothing to a binary variable.

Yes, that is a good idea too, so the thing here is to build a huge amount of constraints (predefined) with all possible indexes, is that the way this works?

So if I have an image, let’s say 500 x 200 mm and I divide ROLE to mm grid, so to assign all 1 (ones) to POSITION system will have to create 500 x 200 constraints, is that?

Honestly, I don’t know… Maybe? I think posing this problem (I looked at the previous threads) as an MIP like you’re doing is more intuitive to conceptualize, but computationally will be difficult to solve. I have been wondering if the problem can be posed as e.g. a geometric program (and solved with Convex.jl), but I don’t know of some simple mapping that will make it so. Anyway, for me this is uncharted territory, so I can’t predict what the results of this approach will be :sweat_smile:
Good luck!

1 Like