syntax = "proto3";

package opvious.formulation;

message Assembly {
  repeated Dimension dimensions = 1;
  repeated Parameter parameters = 2;
  repeated Variable variables = 3;
  repeated Constraint constraints = 4;
  repeated Objective objectives = 5;
}

message Dimension {
  string label = 1;
  bool is_numeric = 2;
}

message Parameter {
  string label = 1;
  repeated string qualifiers = 2; // Label or empty string for default
  TensorSignature signature = 3;
}

message TensorSignature {
  Space domain = 1;
  Image image = 2;
}

message Image {
  bool is_integral = 1;
  Interval interval = 2;
}

message Interval {
  Expression lower_bound = 1;
  Expression upper_bound = 2;
}

message Variable {
  string label = 1;
  repeated string qualifiers = 2; // Label or empty string for default
  TensorSignature signature = 3;
}

message Space {
  repeated Binding bindings = 1;
  Predicate mask = 2;
}

message Binding {
  int32 anchor = 1;
  oneof source {
    string dimension_label = 2;
    Interval range = 3;
  }
}

message Predicate {
  message Satisfies {
    enum Condition {
      UNKNOWN = 0;
      ZERO = 1;
      NON_NEGATIVE = 2;
      NON_POSITIVE = 3;
      NON_ZERO = 4;
      NEGATIVE = 5;
      POSITIVE = 6;
    }
    Condition condition = 1;
    Expression expression = 2;
  }

  message Selects {
    oneof source {
      string dimension_label = 1;
      Interval range = 2;
    }
    Expression expression = 3;
    bool is_member = 4;
  }

  message Connects {
    enum Connective {
      UNKNOWN = 0;
      AND = 1;
      OR = 2;
    }
    Connective connective = 1;
    Predicate left_predicate = 2;
    Predicate right_predicate = 3;
  }

  oneof predicate {
    Satisfies satisfies = 1;
    Selects selects = 2;
    Connects connects = 3;
  }
}

message Constraint {
  string label = 1;
  repeated string qualifiers = 2;
  Space domain = 3;
  Combination combination = 4;
  double lower_bound = 5;
  double upper_bound = 6;
}

message Combination {
  // Constant term
  Expression offset = 1;

  // Non-constant terms
  message Weight {
    repeated Factor factors = 1;
    Coefficient coefficient = 2;
  }
  message Factor {
    string variable_label = 1;
    repeated Expression subscripts = 2;
  }
  repeated Weight weights = 2;
}

message Coefficient {
  Expression value = 1;

  message Over {
    Space domain = 1;
    Coefficient coefficient = 2;
  }
  Over over = 2;
}

message Expression {
  message Input {
    string label = 1;
    repeated Expression subscripts = 2;
  }

  message Unary {
    enum Operator {
      UNKNOWN = 0;
      CEIL = 1;
      FLOOR = 2;
      SQRT = 3;
      INV = 4;
      ABS = 5;
    }
    Operator operator = 1;
    Expression expression = 2;
  }

  message Binary {
    enum Operator {
      UNKNOWN = 0;
      MUL = 1;
      ADD = 2;
      MOD = 3;
      POW = 4;
    }
    Operator operator = 1;
    Expression left_expression = 2;
    Expression right_expression = 3;
  }

  message Sum {
    Space domain = 1;
    Expression expression = 2;
  }

  message Cardinality {
    Space space = 1;
  }

  message Switched {
    message Case {
      Predicate predicate = 1;
      Expression expression = 2;
    }
    repeated Case cases = 1;
  }

  oneof expression {
    double literal = 1;
    Input input = 2;
    int32 anchor = 3;
    Unary unary = 4;
    Binary binary = 5;
    Sum sum = 6;
    Cardinality cardinality = 7;
    Switched switched = 8;
  }
}

message Objective {
  bool is_maximization = 1;
  Combination combination = 2;
  string label = 3;
}
