static bool product_merge_single_term(struct solver_Algebra *a, uint64_t lhs, uint64_t rhs, uint64_t *merged) {
if(is_number(lhs) && is_number(rhs)) {
*merged = number_multiply(a, lhs, rhs);
return true;
}
if(is_number(lhs) && lhs == LITERAL_ZERO) {
*merged = LITERAL_ZERO;
return true;
}
if(is_number(rhs) && rhs == LITERAL_ZERO) {
*merged = LITERAL_ZERO;
return true;
}
if(is_number(lhs) && lhs == LITERAL_ONE) {
*merged = rhs;
return true;
}
if(is_number(rhs) && rhs == LITERAL_ONE) {
*merged = lhs;
return true;
}
return false;
}
static uint64_t embed_product(struct solver_Algebra *a, uint32_t count, const uint64_t *values) {
uint64_t merged;
if(count == 0) return LITERAL_ZERO;
if(count == 1) return values[0];
if(count == 2) {
if(product_merge_single_term(a, values[0], values[1], &merged)) {
return merged;
}
}
uint32_t new_count = 0;
uint64_t * new_values = alias_stack_allocation(sizeof(*new_values) * count, alignof(*new_values));
for(uint32_t i = 0; i < count; i++) {
uint32_t k;
for(k = 0; k < new_count; k++) {
if(product_merge_single_term(a, new_values[k], values[i], &merged)) {
if(merged == LITERAL_ZERO) return LITERAL_ZERO;
new_values[k] = merged;
break;
}
}
if(k == new_count) {
if(values[i] == LITERAL_ZERO) return LITERAL_ZERO;
new_values[new_count++] = values[i];
}
}
if(new_count == 0) return LITERAL_ZERO;
if(new_count == 1) return new_values[0];
if(new_count == 2) {
if(product_merge_single_term(a, new_values[0], new_values[1], &merged)) {
return merged;
}
}
tabula_qsort(new_values, new_count, sizeof(*new_values), qsort_term_compare, a);
struct EncodedList product;
product.count = new_count;
product.index = embed_values(a, new_count, new_values);
return pack_product(product);
}
uint64_t solver_Algebra_product(struct solver_Algebra *a, uint32_t count, const uint64_t *values) {
return embed_product(a, count, values);
}