Restart iteration in a for loop when an error is thrown

I have to run a for loop based on random numbers generation and inversion of a matrix. When the matrix is singular, my code stops, throwing a SingularException() error. If this occurs at a certain iteration of the loop, how can I force the code to restart again the iteration with new numbers generation until a regular matrix is found to continue the loop until the end?

To keep it simple, suppose the following code:

res=zeros(500)
for i=1:length(res) 
    X=rand(100,100)
    X2=transpose(X)*X
    res[i]=tr(inv(X2))
end

If at iteration i the matrix X2 is singular, how can I run again iteration i until the iteration can be completed and then proceed with the loop?

I think you would have to use a while loop instead, with a condition on incrementing i.

1 Like

Ok, I’ll try your solution :wink:

Another possible option is to put the body of the loop into a function and wrap it in a try ... catch block. If an exception is found you call the function again.

So something like:

function my_inner_loop()
   try
      X=rand(100,100)
      X2=transpose(X)*X
      return tr(inv(X2))
   catch
      my_inner_loop()
   end
end

Do I have to call manually the function if an exception is found? Because I want to let the loop running alone in background even when my PC is off.

I think you could do something like this:

    i = 0

function my_inner_loop(;maxtries=100)
    while i < maxtries
        try
          X=rand(100,100)
          X2=transpose(X)*X
          r = tr(inv(X2))
          return r
        catch
          i += 1
          my_inner_loop()
        end
   end
   return nothing # or 0 or whatever makes sense
end

Ok, thanks! I’ll try this solution too :slight_smile: How do I call the function?

I would suggest that you do a QR decomposition of X = QR, so that X'X = R'R, use that to detect invertibility and just return Inf for singular matrices, then work with Rinv = inv(R) etc.

Alternatively, if you are willing to use an SVD,

sum(x -> abs2(1/x), svd(X).S)

is equivalent to tr(inv(X'*X)) because of similarity invariance.

1 Like

After posting the above I realized that there are some scoping issues with the variables. The following code might be closer to what you want for the non-math part:

function my_outerspace_loop(maxtries=100)

    i = 1
    result = nothing
    function my_inner_loop(max)
        # global i
        while i < maxtries
            @show i
            try
                X=rand(100,100)
                X[1,1] < 0.1 || throw()
                X2=transpose(X)*X
                result = tr(inv(X2))
                break
            catch
                println("Trying again...")
                i += 1
                return my_inner_loop(max)
            end
       end
       return (result, i) # or 0 or whatever makes sense
    end

    my_inner_loop(maxtries)
end

Thank you for your suggestion :wink: But I really want to know how to restart an iteration. That’s my central problem.

Thanks. But how can I call this function? my_inner_loop(1) or my_inner_loop() with any number inside ()?

In this case you would call my_outerspace_loop(n) where n is the maximum number of times you want to allow your algorithm to try to find an appropriate solution. You do not call my_inner_loop directly.

Is that what you meant by “how to call”?

1 Like

Yes, that’s what I mean! Thank you! I’ll apply your method!

I accidentally left in some testing stuff. Don’t forget to comment out X[1,1] < 0.1 || throw() or you’ll never get anywhere in life.

1 Like

Ok, perfect!