Ampl weird behavior

Hello I have this model script.

set INPUT_ROW;
set INPUT_TRIANGLES;
set DIM = 1..3;
param data_points {INPUT_ROW, DIM};
param bary_centrics {INPUT_ROW, DIM};
param triangle_points {INPUT_TRIANGLES, DIM};
var move_points {INPUT_ROW, DIM};
minimize energy: sum{i in INPUT_ROW} 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) * 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) ; 

This script works well.

However when I add one term at the end of the minimize function like this:

set INPUT_ROW;
set INPUT_TRIANGLES;
set DIM = 1..3;
param data_points {INPUT_ROW, DIM};
param bary_centrics {INPUT_ROW, DIM};
param triangle_points {INPUT_TRIANGLES, DIM};
var move_points {INPUT_ROW, DIM};
minimize energy: sum{i in INPUT_ROW} 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) * 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) + bary_centrics[i, 1]; 

I got this error.

i is undefined

I don’t know what causes this error. My actual script should be like this:

set INPUT_ROW;
set INPUT_TRIANGLES;
set DIM = 1..3;
param data_points {INPUT_ROW, DIM};
param bary_centrics {INPUT_ROW, DIM};
param triangle_points {INPUT_TRIANGLES, DIM};
var move_points {INPUT_ROW, DIM};
minimize energy: sum{i in INPUT_ROW} 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) * 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) + 
 (bary_centrics[i, 1] * move_points[i, 2] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 2] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 2] - data_points[i, 2]) * 
 (bary_centrics[i, 1] * move_points[i, 2] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 2] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 2] - data_points[i, 2]) + 
 (bary_centrics[i, 1] * move_points[i, 3] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 3] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 3] - data_points[i, 3]) * 
 (bary_centrics[i, 1] * move_points[i, 1] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 3] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 3] - data_points[i, 3]); 

Is it because my objective function is too long? If so, is there a way to make a function and use it in the objective function?

My objective function is getting one vertex position with barycentric coordinates and 3 points and then minimizing the length of the two vertices between the evaluated vertex position and the data points. It’s just a simple linear least squares problem. Anyone know how to write this easily? I think it would be better to use a function that can be used in the objective function.


I changed the minimize function like this, and it works. I don’t know why it works. Can anyone let me know the reason? :

minimize energy: sum{i in INPUT_ROW} 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) * 
 (bary_centrics[i, 1] * move_points[i, 1] + 
  bary_centrics[i, 2] * triangle_points[i * 2 - 1, 1] + 
  bary_centrics[i, 3] * triangle_points[i * 2, 1] - data_points[i, 1]) + 

sum{i in INPUT_ROW} 
 (bary_centrics[i, 1] * move_points[i, 2] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 2] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 2] - data_points[i, 2]) * 
 (bary_centrics[i, 1] * move_points[i, 2] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 2] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 2] - data_points[i, 2]) + 

sum{i in INPUT_ROW} 
 (bary_centrics[i, 1] * move_points[i, 3] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 3] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 3] - data_points[i, 3]) * 
 (bary_centrics[i, 1] * move_points[i, 1] + 
 bary_centrics[i, 2] * triangle_points[i * 2 - 1, 3] + 
 bary_centrics[i, 3] * triangle_points[i * 2, 3] - data_points[i, 3]); 

The i variable seems to be going out of scope. You can fix this with additional parentheses around the objective. Something like
minimize energy: sum{i in INPUT_ROW}(...)
It’s not clear to me if it’s possible to simplify the objective function. It should be, as there are 1s, 2s and 3s that probably could be indexed. Would it be possible to provide the mathematical definition of the objective function and perhaps some minimal data?

1 Like

Thank you for your response. As you recommended, it worked with the additional parentheses. I think the error without the additional parentheses is my grammar error or it might be a error from the parsing code of the AMPL. I can’t know the reason why the equation does not work without the parentheses. Anyway, thank you for letting me know it!

I’m currently studying this paper (https://hhoppe.com/proj/meshopt/). The problem I want to solve is

\begin{split} E(K,V,B) &= E_{dist}(K, V) + E_{spring}(K, V) \\ &= \sum^n_{i=1} || \mathbf{x}_i - \phi_V(\mathbf{b}_i)||^2 + E_{spring}(K, V) \\ &= \sum^n_{i=1} || \mathbf{x}_i - \phi_V(\mathbf{b}_i) ||^2 + \sum_{\{j,k\} \in K} \kappa ||\mathbf{v}_j - \mathbf{v}_k ||^2 \end{split}

The code I wrote before is the version of solving the problem in the local context of mesh vertices, which means you get only one vertex to solve the energy function. I’m trying to solve this in the global context too by considering all of the vertices at once with the ampl solvers. So, the AMPL code might be different for the global context, but they are similar.

I guess that I could solve this problem for each axis (x-axis, y-axis, z-axis) to simplify the codes. The meaning of simplifying the code is that I think the readability will be better if I can use something like get_vector(index) -> return vector from the row i of a matrix, length_vector(vector) -> return the length of the vector, dist(vector_1, vector2) -> return the distance between two vectors. But currently what I know is just to write all the functions manually to do this. So I just wish that I can use a custom user function in the minimization function.

I also added another question to solve the linear least squares problem in here (How to solve a linear least squares problem in a dense/sparse format). I think it’s not easy to write a code to solve this problem.

1 Like

If we simplify your original code we get something like
minimize energy: sum{i in INPUT_ROW}(x[i])*(y[i]) + z[i];
Note that the z variable is out of the scope of the summation and the additional parentheses are needed to fix the issue.

I think that in the linked post @marcos gave a good overview on how to get the rows of a matrix and express a distance function. Note that you need to keep your model as close to mathematical notation as possible, so that the majority solvers are able to understand it.

To improve readability it’s also possible to separate the summations in your objective function, for example something like

param n := 10;
param m := 10;

var x{1..n, 1..m} binary;
var y{1..n} binary;

maximize obj: sum{i in 1..n, j in 1..m} x[i,j] + sum{i in 1..n} y[i];

can be written as

param n := 10;
param m := 10;

var x{1..n, 1..m} binary;
var y{1..n} binary;

var sum_1 = sum{i in 1..n, j in 1..m} x[i,j];
var sum_2 = sum{i in 1..n} y[i];

maximize obj: sum_1 + sum_2;
2 Likes

Okay. I’ve understood why it outputs the error. It seems better to start with one parentheses for the summation. Thanks.

Thank you for your tips! That’s what I was looking for.

I appreciate your help @Nicolau_Santos !

1 Like