static uint64_t boolean_not(const struct solver_Algebra *a, uint64_t expr_) {
  if(expr_ == (TAG_ATOM_BITS | 0)) return TAG_ATOM_BITS | 1;
  if(expr_ == (TAG_ATOM_BITS | 1)) return TAG_ATOM_BITS | 0;
  return TAG_ATOM_BITS | 2;
}

static bool equals(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs);

static bool equals__real__real(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return unpack_real(lhs) == unpack_real(rhs);
}

static bool equals__real(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Real:
    return equals__real__real(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__variable__variable(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return alias_str_same(unpack_variable(lhs), unpack_variable(rhs));
}

static bool equals__variable(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Variable:
    return equals__variable__variable(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__boolean__boolean(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return unpack_boolean(lhs) == unpack_boolean(rhs);
}

static bool equals__boolean(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Boolean:
    return equals__boolean__boolean(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__undefined__undefined(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  unpack_undefined(lhs);
  unpack_undefined(rhs);
  return true;
}

static bool equals__undefined(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Undefined:
    return equals__undefined__undefined(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__smallint__smallint(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return unpack_smallint(lhs) == unpack_smallint(rhs);
}

static bool equals__smallint(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_SmallInt:
    return equals__smallint__smallint(a, lhs, rhs);
  default:
    return false;
  }
}
static bool equals__largeint__largeint(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) { return false; }
static bool equals__largeint(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_LargeInt:
    return equals__largeint__largeint(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__fraction__fraction(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) { return false; }
static bool equals__fraction(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Fraction:
    return equals__fraction__fraction(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__power__power(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return equals(a, get_car(a, lhs), get_car(a, rhs)) && equals(a, get_cdr(a, lhs), get_cdr(a, rhs));
}

static bool equals__power(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Power:
    return equals__power__power(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__sum__sum(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  uint32_t count = get_list_count(lhs);
  if(count != get_list_count(rhs)) {
    return false;
  }
  for(uint32_t i = 0; i < count; i++) {
    if(!equals(a, get_index(a, lhs, i), get_index(a, rhs, i))) {
      return false;
    }
  }
  return true;
}

static bool equals__sum(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Sum:
    return equals__sum__sum(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__product__product(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  uint32_t count = get_list_count(lhs);
  if(count != get_list_count(rhs)) {
    return false;
  }
  for(uint32_t i = 0; i < count; i++) {
    if(!equals(a, get_index(a, lhs, i), get_index(a, rhs, i))) {
      return false;
    }
  }
  return true;
}

static bool equals__product(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Product:
    return equals__product__product(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__equals__equals(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return equals(a, get_car(a, lhs), get_car(a, rhs)) &&
         equals(a, get_cdr(a, lhs), get_cdr(a, rhs));
}

static bool equals__equals(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_Equals:
    return equals__equals__equals(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__not_equals__not_equals(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return equals(a, get_car(a, lhs), get_car(a, rhs)) && equals(a, get_cdr(a, lhs), get_cdr(a, rhs));
}

static bool equals__not_equals(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_NotEquals:
    return equals__not_equals__not_equals(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__less_than__less_than(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return equals(a, get_car(a, lhs), get_car(a, rhs)) && equals(a, get_cdr(a, lhs), get_cdr(a, rhs));
}

static bool equals__less_than(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_LessThan:
    return equals__less_than__less_than(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals__greater_than__greater_than(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  return equals(a, get_car(a, lhs), get_car(a, rhs)) && equals(a, get_cdr(a, lhs), get_cdr(a, rhs));
}

static bool equals__greater_than(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  switch(get_tag(rhs)) {
  case Tag_GreaterThan:
    return equals__greater_than__greater_than(a, lhs, rhs);
  default:
    return false;
  }
}

static bool equals(const struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  if(lhs == rhs) return true;
  switch(get_tag(lhs)) {
  case Tag_Real:
    return equals__real(a, lhs, rhs);
  case Tag_Variable:
    return equals__variable(a, lhs, rhs);
  case Tag_Boolean:
    return equals__boolean(a, lhs, rhs);
  case Tag_Undefined:
    return equals__undefined(a, lhs, rhs);
  case Tag_SmallInt:
    return equals__smallint(a, lhs, rhs);
  case Tag_LargeInt:
    return equals__largeint(a, lhs, rhs);
  case Tag_Fraction:
    return equals__fraction(a, lhs, rhs);
  case Tag_Power:
    return equals__power(a, lhs, rhs);
  case Tag_Sum:
    return equals__sum(a, lhs, rhs);
  case Tag_Product:
    return equals__product(a, lhs, rhs);
  case Tag_Equals:
    return equals__equals(a, lhs, rhs);
  case Tag_NotEquals:
    return equals__not_equals(a, lhs, rhs);
  case Tag_LessThan:
    return equals__less_than(a, lhs, rhs);
  case Tag_GreaterThan:
    return equals__greater_than(a, lhs, rhs);
  default:
    return false;
  }
}

uint64_t solver_Algebra_boolean(struct solver_Algebra *a, bool value) {
  return pack_boolean(value);
}

uint64_t solver_Algebra_equals(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  uint64_t values[2] = { lhs, rhs };
  uint32_t index = embed_values(a, 2, values);
  return pack_equals(index);
}

uint64_t solver_Algebra_not_equals(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  uint64_t values[2] = { lhs, rhs };
  uint32_t index = embed_values(a, 2, values);
  return pack_not_equals(index);
}

uint64_t solver_Algebra_less_than(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  uint64_t values[2] = { lhs, rhs };
  uint32_t index = embed_values(a, 2, values);
  return pack_less_than(index);
}

uint64_t solver_Algebra_greater_than(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs) {
  uint64_t values[2] = { lhs, rhs };
  uint32_t index = embed_values(a, 2, values);
  return pack_greater_than(index);
}