1 /******************************************************************************
2 * Top contributors (to current version):
5 * This file is part of the cvc5 project.
7 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8 * in the top-level source directory and their institutional affiliations.
9 * All rights reserved. See the file COPYING in the top-level source
10 * directory for licensing information.
11 * ****************************************************************************
13 * Arithmetic utility for polynomial normalization
16 #include "theory/arith/arith_poly_norm.h"
18 using namespace cvc5::kind
;
24 void PolyNorm::addMonomial(TNode x
, const Rational
& c
, bool isNeg
)
27 std::unordered_map
<Node
, Rational
>::iterator it
= d_polyNorm
.find(x
);
28 if (it
== d_polyNorm
.end())
30 d_polyNorm
[x
] = isNeg
? -c
: c
;
33 Rational
res(it
->second
+ (isNeg
? -c
: c
));
45 void PolyNorm::multiplyMonomial(TNode x
, const Rational
& c
)
50 // multiply by constant
51 for (std::pair
<const Node
, Rational
>& m
: d_polyNorm
)
53 // c1*x*c2 = (c1*c2)*x
59 std::unordered_map
<Node
, Rational
> ptmp
= d_polyNorm
;
61 for (const std::pair
<const Node
, Rational
>& m
: ptmp
)
63 // c1*x1*c2*x2 = (c1*c2)*(x1*x2)
64 Node newM
= multMonoVar(m
.first
, x
);
65 d_polyNorm
[newM
] = m
.second
* c
;
70 void PolyNorm::add(const PolyNorm
& p
)
72 for (const std::pair
<const Node
, Rational
>& m
: p
.d_polyNorm
)
74 addMonomial(m
.first
, m
.second
);
78 void PolyNorm::subtract(const PolyNorm
& p
)
80 for (const std::pair
<const Node
, Rational
>& m
: p
.d_polyNorm
)
82 addMonomial(m
.first
, m
.second
, true);
86 void PolyNorm::multiply(const PolyNorm
& p
)
88 if (p
.d_polyNorm
.size() == 1)
90 for (const std::pair
<const Node
, Rational
>& m
: p
.d_polyNorm
)
92 multiplyMonomial(m
.first
, m
.second
);
97 // If multiplying by sum, must distribute; if multiplying by zero, clear.
98 // First, remember the current state and clear.
99 std::unordered_map
<Node
, Rational
> ptmp
= d_polyNorm
;
101 for (const std::pair
<const Node
, Rational
>& m
: p
.d_polyNorm
)
104 pbase
.d_polyNorm
= ptmp
;
105 pbase
.multiplyMonomial(m
.first
, m
.second
);
106 // add this to current
112 void PolyNorm::clear() { d_polyNorm
.clear(); }
114 bool PolyNorm::empty() const { return d_polyNorm
.empty(); }
116 bool PolyNorm::isEqual(const PolyNorm
& p
) const
118 if (d_polyNorm
.size() != p
.d_polyNorm
.size())
122 std::unordered_map
<Node
, Rational
>::const_iterator it
;
123 for (const std::pair
<const Node
, Rational
>& m
: d_polyNorm
)
125 Assert(m
.second
.sgn() != 0);
126 it
= p
.d_polyNorm
.find(m
.first
);
127 if (it
== p
.d_polyNorm
.end() || m
.second
!= it
->second
)
135 Node
PolyNorm::multMonoVar(TNode m1
, TNode m2
)
137 std::vector
<TNode
> vars
= getMonoVars(m1
);
138 std::vector
<TNode
> vars2
= getMonoVars(m2
);
139 vars
.insert(vars
.end(), vars2
.begin(), vars2
.end());
145 else if (vars
.size() == 1)
149 // use default sorting
150 std::sort(vars
.begin(), vars
.end());
151 return NodeManager::currentNM()->mkNode(NONLINEAR_MULT
, vars
);
154 std::vector
<TNode
> PolyNorm::getMonoVars(TNode m
)
156 std::vector
<TNode
> vars
;
157 // m is null if this is the empty variable (for constant monomials)
160 Kind k
= m
.getKind();
161 Assert(k
!= CONST_RATIONAL
);
162 if (k
== MULT
|| k
== NONLINEAR_MULT
)
164 vars
.insert(vars
.end(), m
.begin(), m
.end());
174 PolyNorm
PolyNorm::mkPolyNorm(TNode n
)
176 Assert(n
.getType().isRealOrInt());
179 std::unordered_map
<TNode
, PolyNorm
> visited
;
180 std::unordered_map
<TNode
, PolyNorm
>::iterator it
;
181 std::vector
<TNode
> visit
;
187 it
= visited
.find(cur
);
188 Kind k
= cur
.getKind();
189 if (it
== visited
.end())
191 if (k
== CONST_RATIONAL
)
193 Rational r
= cur
.getConst
<Rational
>();
196 // zero is not an entry
197 visited
[cur
] = PolyNorm();
201 visited
[cur
].addMonomial(null
, r
);
204 else if (k
== ADD
|| k
== SUB
|| k
== NEG
|| k
== MULT
205 || k
== NONLINEAR_MULT
)
207 visited
[cur
] = PolyNorm();
208 for (const Node
& cn
: cur
)
216 visited
[cur
].addMonomial(cur
, one
);
222 if (it
->second
.empty())
224 PolyNorm
& ret
= visited
[cur
];
232 for (size_t i
= 0, nchild
= cur
.getNumChildren(); i
< nchild
; i
++)
234 it
= visited
.find(cur
[i
]);
235 Assert(it
!= visited
.end());
236 if ((k
== SUB
&& i
== 1) || k
== NEG
)
238 ret
.subtract(it
->second
);
240 else if (i
> 0 && (k
== MULT
|| k
== NONLINEAR_MULT
))
242 ret
.multiply(it
->second
);
250 case CONST_RATIONAL
: break;
251 default: Unhandled() << "Unhandled polynomial operation " << cur
; break;
254 } while (!visit
.empty());
255 Assert(visited
.find(n
) != visited
.end());
259 bool PolyNorm::isArithPolyNorm(TNode a
, TNode b
)
261 PolyNorm pa
= PolyNorm::mkPolyNorm(a
);
262 PolyNorm pb
= PolyNorm::mkPolyNorm(b
);
263 return pa
.isEqual(pb
);
267 } // namespace theory