RCP<const Basic> mul_expand(const RCP<const Mul> &self) { RCP<const Basic> a, b; self->as_two_terms(outArg(a), outArg(b)); a = expand(a); b = expand(b); return mul_expand_two(a, b); }
RCP<const Basic> mul_expand_two(const RCP<const Basic> &a, const RCP<const Basic> &b) { // Both a and b are assumed to be expanded if (is_a<Add>(*a) && is_a<Add>(*b)) { RCP<const Number> coef = mulnum(rcp_static_cast<const Add>(a)->coef_, rcp_static_cast<const Add>(b)->coef_); umap_basic_num d; // Improves (x+1)^3(x+2)^3...(x+350)^3 expansion from 0.97s to 0.93s: d.reserve((rcp_static_cast<const Add>(a))->dict_.size()* (rcp_static_cast<const Add>(b))->dict_.size()); // Expand dicts first: for (auto &p: (rcp_static_cast<const Add>(a))->dict_) { for (auto &q: (rcp_static_cast<const Add>(b))->dict_) { // The main bottleneck here is the mul(p.first, q.first) command RCP<const Basic> term = mul(p.first, q.first); if (is_a_Number(*term)) { iaddnum(outArg(coef), rcp_static_cast<const Number>(term)); } else { Add::dict_add_term(d, mulnum(p.second, q.second), term); } } Add::dict_add_term(d, mulnum(rcp_static_cast<const Add>(b)->coef_, p.second), p.first); } // Handle the coefficient of "a": for (auto &q: (rcp_static_cast<const Add>(b))->dict_) { Add::dict_add_term(d, mulnum(rcp_static_cast<const Add>(a)->coef_, q.second), q.first); } return Add::from_dict(coef, std::move(d)); } else if (is_a<Add>(*a)) { return mul_expand_two(b, a); } else if (is_a<Add>(*b)) { RCP<const Number> a_coef; RCP<const Basic> a_term; Add::as_coef_term(a, outArg(a_coef), outArg(a_term)); RCP<const Number> coef = zero; umap_basic_num d; d.reserve((rcp_static_cast<const Add>(b))->dict_.size()); for (auto &q: (rcp_static_cast<const Add>(b))->dict_) { RCP<const Basic> term = mul(a_term, q.first); if (is_a_Number(*term)) { iaddnum(outArg(coef), rcp_static_cast<const Number>(term)); } else { Add::dict_add_term(d, mulnum(a_coef, q.second), term); } } if (eq(a_term, one)) { iaddnum(outArg(coef), mulnum(rcp_static_cast<const Add>(b)->coef_, a_coef)); } else { Add::dict_add_term(d, mulnum(rcp_static_cast<const Add>(b)->coef_, a_coef), a_term); } return Add::from_dict(coef, std::move(d)); } return mul(a, b); }
RCP<const Basic> mul_expand_two(const RCP<const Basic> &a, const RCP<const Basic> &b) { // Both a and b are assumed to be expanded if (is_a<Add>(*a) && is_a<Add>(*b)) { RCP<const Number> coef = mulnum(rcp_static_cast<const Add>(a)->coef_, rcp_static_cast<const Add>(b)->coef_); umap_basic_num d; // Improves (x+1)**3*(x+2)**3*...(x+350)**3 expansion from 0.97s to 0.93s: d.reserve((rcp_static_cast<const Add>(a))->dict_.size()* (rcp_static_cast<const Add>(b))->dict_.size()); // Expand dicts first: for (auto &p: (rcp_static_cast<const Add>(a))->dict_) { for (auto &q: (rcp_static_cast<const Add>(b))->dict_) { // The main bottleneck here is the mul(p.first, q.first) command RCP<const Basic> term = mul(p.first, q.first); if (is_a_Number(*term)) { iaddnum(outArg(coef), mulnum(mulnum(p.second, q.second), rcp_static_cast<const Number>(term))); } else { if (is_a<Mul>(*term) && !(rcp_static_cast<const Mul>(term)->coef_->is_one())) { // Tidy up things like {2x: 3} -> {x: 6} RCP<const Number> coef2 = rcp_static_cast<const Mul>(term)->coef_; // We make a copy of the dict_: map_basic_basic d2 = rcp_static_cast<const Mul>(term)->dict_; term = Mul::from_dict(one, std::move(d2)); Add::dict_add_term(d, mulnum(mulnum(p.second, q.second), coef2), term); } else { Add::dict_add_term(d, mulnum(p.second, q.second), term); } } } Add::dict_add_term(d, mulnum(rcp_static_cast<const Add>(b)->coef_, p.second), p.first); } // Handle the coefficient of "a": for (auto &q: (rcp_static_cast<const Add>(b))->dict_) { Add::dict_add_term(d, mulnum(rcp_static_cast<const Add>(a)->coef_, q.second), q.first); } return Add::from_dict(coef, std::move(d)); } else if (is_a<Add>(*a)) { return mul_expand_two(b, a); } else if (is_a<Add>(*b)) { RCP<const Number> a_coef; RCP<const Basic> a_term; Add::as_coef_term(a, outArg(a_coef), outArg(a_term)); RCP<const Number> coef = zero; umap_basic_num d; d.reserve((rcp_static_cast<const Add>(b))->dict_.size()); for (auto &q: (rcp_static_cast<const Add>(b))->dict_) { RCP<const Basic> term = mul(a_term, q.first); if (is_a_Number(*term)) { iaddnum(outArg(coef), mulnum(mulnum(q.second, a_coef), rcp_static_cast<const Number>(term))); } else { if (is_a<Mul>(*term) && !(rcp_static_cast<const Mul>(term)->coef_->is_one())) { // Tidy up things like {2x: 3} -> {x: 6} RCP<const Number> coef2 = rcp_static_cast<const Mul>(term)->coef_; // We make a copy of the dict_: map_basic_basic d2 = rcp_static_cast<const Mul>(term)->dict_; term = Mul::from_dict(one, std::move(d2)); Add::dict_add_term(d, mulnum(mulnum(q.second, a_coef), coef2), term); } else { Add::dict_add_term(d, mulnum(a_coef, q.second), term); } } } if (eq(*a_term, *one)) { iaddnum(outArg(coef), mulnum(rcp_static_cast<const Add>(b)->coef_, a_coef)); } else { Add::dict_add_term(d, mulnum(rcp_static_cast<const Add>(b)->coef_, a_coef), a_term); } return Add::from_dict(coef, std::move(d)); } return mul(a, b); }