-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdyn_math_object.h
More file actions
258 lines (200 loc) · 10.8 KB
/
dyn_math_object.h
File metadata and controls
258 lines (200 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#pragma once
/****************************************************************************
** Copyright (c) 2023, Adel Kara Slimane <adel.ks@zegrapher.com>
**
** This file is part of ZeCalculator's source code.
**
** ZeCalculators is free software: you may copy, redistribute and/or modify it
** under the terms of the GNU Affero General Public License as published by the
** Free Software Foundation, either version 3 of the License, or (at your
** option) any later version.
**
** This file is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include <zecalculator/error.h>
#include <zecalculator/evaluation/decl/cache.h>
#include <zecalculator/external/expected.h>
#include <zecalculator/math_objects/object_list.h>
#include <zecalculator/parsing/data_structures/decl/utils.h>
#include <zecalculator/parsing/data_structures/deps.h>
#include <zecalculator/parsing/decl/utils.h>
#include <zecalculator/parsing/types.h>
namespace zc {
template <parsing::Type type>
class MathWorld;
namespace parsing {
template <Type>
struct make_fast;
template <parsing::Type>
struct FunctionVisiter;
template <parsing::Type>
struct VariableVisiter;
}
enum ObjectType {BAD_EQUATION, CONSTANT, CPP_FUNCTION, FUNCTION, SEQUENCE, DATA};
template <parsing::Type type>
class DynMathObject
{
public:
/// @brief assign equation and automatically deduce the object type the equation defines
/// @note this method can potentially modify every other DynMathObject in the same MathWorld
DynMathObject<type>& operator = (std::string eq);
/// @brief changes the name of the object
/// @note if the name is already taken, then the name becomes free, user needs to call this function again
/// @note does not update the name within the equation string, if there is one. Errors will may have a wrong offset because of that
DynMathObject<type>& set_name(std::string_view name);
/// @brief assign equation and automatically deduce the object type the equation defines
/// @note 'name' should not be a function call
/// @note this method can potentially modify every other DynMathObject in the same MathWorld
template <size_t args_num>
DynMathObject<type>& set(std::string_view name, CppFunction<args_num> cpp_f);
template <size_t args_num>
DynMathObject<type>& operator = (CppFunction<args_num> cpp_f);
/// @brief define the object as a global constant of value 'value'
/// @note 'name' should not be a function call
/// @note this method can potentially modify every other DynMathObject in the same MathWorld
DynMathObject<type>& set(std::string_view name, double value);
DynMathObject<type>& operator = (double value);
/// @brief overwrite the object's internal data with the given data
/// @param name: new name of the object
/// @param data: each data point as a string (number or generic expression, that can depend on other objects)
/// @note this method can potentially modify every other DynMathObject in the same MathWorld
DynMathObject<type>& set_data(std::string_view name, std::vector<std::string> data);
/// @brief change one single data point in the object
/// @note if the object did not hold any data beforehand,
/// it's transformed into a data object with the same name (if it had a valid one)
DynMathObject<type>& set_data_point(size_t index, std::string expr);
/// @brief Overwrites data points
/// @param index: index of the first point to overwrite, the rest follows contiguously
DynMathObject<type>& set_data_points(size_t index, std::vector<std::string> data);
/// @brief Inserts data point
/// @param index: index of the point after insertion
/// @note All points whose index > 'index' before the insertion
/// will have their index incremented after the insertion
DynMathObject<type>& insert_data_point(size_t index, std::string expr);
/// @brief Inserts data point
/// @param index: index of the first point after insertion, the rest follows contiguously
/// @note All points whose index > 'index' before the insertion
/// will be moved data.size() cells after the insertion
DynMathObject<type>& insert_data_points(size_t index, std::vector<std::string> data);
/// @brief Removes a data point
/// @param index: index of the point to remove
/// @note All points whose index > 'index' before the removal
/// will be moved back by one spot
DynMathObject<type>& remove_data_point(size_t index);
/// @brief Removes several contiguous data points
/// @param index: index of the first point to remove
/// @param count: how many points contiguous to remove starting 'index'
/// @note if index + count >= size(), all points starting 'index' will be removed regardless
DynMathObject<type>& remove_data_points(size_t index, size_t count);
/// @brief Retrieve the text of a data point, if it exists
/// @note To retrieve the actual evaluation, evaluate this object at the same index
std::optional<std::string> get_data_point(size_t index) const;
tl::expected<double, Error> operator () (std::initializer_list<double> vals = {}, eval::Cache* cache = nullptr) const;
tl::expected<double, Error> evaluate(std::initializer_list<double> vals = {}, eval::Cache* cache = nullptr) const;
/// @brief returns the currently set name, regardless of the validity of the object
/// @note returns non-empty string only if the object has been assigned a valid unique name
std::string_view get_name() const;
/// @brief returns the names of the variables that are used as input to the function
/// @note empty if there are not
std::vector<std::string> get_input_var_names() const;
/// @returns the type of the object held by this instance
ObjectType object_type() const;
/// @returns the number of updates this object has gone through
/// @note this function's usefulness is to know if the object is still the "same" or got changed meanwhile
/// @example 'f(x)=cos(x)+c' and 'c=3' originally but then 'c=4', which will increment the revision of 'f'
size_t get_revision() const;
/// @returns true if the instance is currently of that type, regardless of its validity
bool holds(ObjectType obj_type) const;
/// @brief returns true if name_status() and object_status() are okay;
operator bool () const;
/// @brief same as operator bool()
bool has_value () const { return bool(*this); }
/// @brief returns the status of the name / "Left hand side" of the object
tl::expected<Ok, zc::Error> name_status() const;
/// @brief returns the status of the object / "right hand side" of the object
tl::expected<Ok, zc::Error> object_status() const;
/// @brief returns the overall status of the object, aka rhs and lhs
tl::expected<Ok, zc::Error> status() const;
/// @brief returns either the error reported by name_status() or object_status(), if there is one
std::optional<zc::Error> error() const;
/// @brief gives the Functions and Variables the expression(s) of this object directly depends on
/// @note uses only the expression(s) this object is defined with
/// -> undefined functions & variables in the math world will still be listed
/// @note this function is non-const because dependencies are cached and this function may trigger caching
const deps::Deps& direct_dependencies();
/// @brief gets the size of the contained data object, if a data object is contained
std::optional<size_t> get_data_size() const;
/// @brief returns object's slot within its owning MathWorld
size_t get_slot() const { return slot; }
/// @brief gets the equation assigned to the object, if there is one
std::optional<std::string> get_equation() const;
using LinkedRepr = std::variant<CppFunction<1>,
CppFunction<2>,
const double*,
const parsing::LinkedFunc<type>*,
const parsing::LinkedSeq<type>*,
const parsing::LinkedData<type>*>;
/// @brief returns the internal linked representation, if there's one
/// @note this function is offered for debugging purposes / advanced use
tl::expected<LinkedRepr, zc::Error> get_linked_repr() const;
protected:
const size_t slot;
MathWorld<type>& mathworld;
/// @brief How many times this object has been updates, either directly, or one if its dependencies have changed
size_t revision = 0;
/// @brief direct dependencies of this object
deps::Deps direct_deps;
/// @brief at which revision number the saved direct_deps have been computed
size_t direct_deps_revision = 0;
struct ConstObj {
double val;
std::optional<std::string> rhs_str = {};
};
struct FuncObj {
/// @brief the string also contains the equal sign that acts as a separator
std::string rhs_str;
parsing::AST rhs;
tl::expected<parsing::LinkedFunc<type>, zc::Error> linked_rhs = tl::unexpected(
zc::Error::empty_expression());
};
struct SeqObj {
std::string rhs_str;
std::vector<parsing::AST> rhs = {};
tl::expected<parsing::LinkedSeq<type>, zc::Error> linked_rhs = tl::unexpected(
zc::Error::empty_expression());
};
struct DataObj {
std::vector<std::string> data = {};
std::vector<tl::expected<parsing::AST, zc::Error>> rhs = {};
parsing::LinkedData<type> linked_rhs = {};
};
std::variant<zc::Error, ConstObj, FuncObj, SeqObj, DataObj, CppFunction<1>, CppFunction<2>>
parsed_data = zc::Error::empty_expression();
std::string lhs_str;
tl::expected<parsing::LHS, zc::Error> exp_lhs = tl::unexpected(zc::Error::empty_expression());
DynMathObject(size_t slot, MathWorld<type>& mathworld): slot(slot), mathworld(mathworld) {};
/// @brief updates the name of the object without notifying the MathWorld instance about it
template <class T>
requires (std::is_same_v<T, parsing::AST> or std::is_convertible_v<T, std::string_view>)
void set_name_internal(const T& name, std::string_view full_expr);
template <bool insert>
DynMathObject<type>& bulk_data_input(size_t index, std::vector<std::string> data);
tl::expected<zc::parsing::Parsing<type>, zc::Error> get_final_repr(const parsing::AST& ast,
std::string_view equation);
/// @tparam linked: link with other math objects, otherwise assigns unlinked alternative
template <bool link = true>
DynMathObject<type>& finalize_asts();
void increment_revision();
friend MathWorld<type>;
friend struct parsing::FunctionVisiter<type>;
friend struct parsing::VariableVisiter<type>;
friend struct parsing::make_fast<type>;
};
} // namespace zc