// returns ¯∞ up to 0 for for less than, 0 for equals, then up to ∞ for greater than
static int term_compare(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs);

static int term_compare_lists_from_end(struct solver_Algebra *a, uint32_t l, const uint64_t *lhs, uint32_t r, const uint64_t *rhs) {
  for(;; --l, --r) {
    if(l == 0) return 1;
    if(r == 0) return -1;
    int cmp = term_compare(a, lhs[l], rhs[r]);
    if(cmp != 0) {
      return cmp;
    }
  }
}

static bool term_compare_0(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs, int *result) {
  uint32_t l, r;
  const uint64_t *l_values, *r_values;
  
  if(is_product(lhs)) {
    l = get_list_count(lhs);
    l_values = a->values.data + get_list_index(lhs);

    if(is_product(rhs)) {
      r = get_list_count(rhs);
      r_values = a->values.data + get_list_index(rhs);
    } else if(is_power(rhs) || is_sum(rhs) || is_variable(rhs)) {
      r = 1;
      r_values = &rhs;
    } else {
      return false;
    }

    *result = term_compare_lists_from_end(a, l, l_values, r, r_values);
    return true;
  }

  if(is_power(lhs)) {
    l = 2;
    l_values = a->values.data + get_pair_index(lhs);

    if(is_power(rhs)) {
      r = 2;
      r_values = a->values.data + get_pair_index(rhs);
    } else if(is_sum(rhs) || is_variable(rhs)) {
      r = 1;
      r_values = &rhs;
    } else {
      return false;
    }

    *result = term_compare_lists_from_end(a, l, l_values, r, r_values);
    return true;
  }

  if(is_sum(lhs)) {
    l = get_list_count(lhs);
    l_values = a->values.data + get_list_index(lhs);

    if(is_sum(rhs)) {
      r = get_list_count(rhs);
      r_values = a->values.data + get_list_index(rhs);
    } else if(is_variable(rhs)) {
      r = 1;
      r_values = &rhs;
    } else {
      return false;
    }

    *result = term_compare_lists_from_end(a, l, l_values, r, r_values);
    return true;
  }

  return false;
}

static int term_compare(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  if(is_number(lhs)) {
    if(is_number(rhs)) {
      return number_compare(a, lhs, rhs);
    } else {
      return -1;
    }
  } else if(is_number(rhs)) {
    return 1;
  }


  if(is_variable(lhs) && is_variable(rhs)) {
    return strcmp(unpack_variable(lhs), unpack_variable(rhs));
  }

  int result;
  if(term_compare_0(a, lhs, rhs, &result)) return result;
  if(term_compare_0(a, rhs, lhs, &result)) return -result;
  assert(false);
  return 0;
}