Fix build
[LibreOffice.git] / sc / inc / scmatrix.hxx
blob2b0a6e64c32a7b3acfcef5965653dabcbead1ca6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #pragma once
22 #include "address.hxx"
23 #include "matrixoperators.hxx"
24 #include "types.hxx"
25 #include <formula/errorcodes.hxx>
26 #include "scdllapi.h"
27 #include <svl/sharedstring.hxx>
28 #include <svl/sharedstringpool.hxx>
30 #include <memory>
31 #include <utility>
32 #include <vector>
34 #define DEBUG_MATRIX 0
36 class ScInterpreter;
37 struct ScInterpreterContext;
38 class ScMatrixImpl;
39 enum class FormulaError : sal_uInt16;
41 namespace sc {
43 struct Compare;
44 struct CompareOptions;
48 /**
49 * Try NOT to use this struct. This struct should go away in a hopefully
50 * not so distant future.
52 struct ScMatrixValue
54 double fVal;
55 svl::SharedString aStr;
56 ScMatValType nType;
58 /// Only valid if ScMatrix methods indicate so!
59 const svl::SharedString& GetString() const { return aStr; }
61 /// Only valid if ScMatrix methods indicate that this is no string!
62 FormulaError GetError() const { return GetDoubleErrorValue(fVal); }
64 /// Only valid if ScMatrix methods indicate that this is a boolean
65 bool GetBoolean() const { return fVal != 0.0; }
67 ScMatrixValue() : fVal(0.0), nType(ScMatValType::Empty) {}
68 ScMatrixValue(const ScMatrixValue& r) = default;
69 ScMatrixValue& operator= (const ScMatrixValue& r) = default;
71 bool operator== (const ScMatrixValue& r) const
73 if (nType != r.nType)
74 return false;
76 switch (nType)
78 case ScMatValType::Value:
79 case ScMatValType::Boolean:
80 return fVal == r.fVal;
81 break;
82 default:
86 return aStr == r.aStr;
89 bool operator!= (const ScMatrixValue& r) const
91 return !operator==(r);
95 /**
96 * Matrix data type that can store values of mixed types. Each element can
97 * be one of the following types: numeric, string, boolean, empty, and empty
98 * path.
100 class ScMatrix final
102 friend class ScMatrixImpl;
104 mutable size_t nRefCnt; // reference count
105 mutable bool mbCloneIfConst; // Whether the matrix is cloned with a CloneIfConst() call.
106 std::unique_ptr<ScMatrixImpl> pImpl;
108 ScMatrix( const ScMatrix& ) = delete;
109 ScMatrix& operator=( const ScMatrix&) = delete;
111 public:
112 SC_DLLPUBLIC ScMatrix(SCSIZE nC, SCSIZE nR);
113 SC_DLLPUBLIC ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal);
114 ScMatrix( size_t nC, size_t nR, const std::vector<double>& rInitVals );
115 ~ScMatrix();
117 typedef std::function<void(size_t, size_t, double)> DoubleOpFunction;
118 typedef std::function<void(size_t, size_t, bool)> BoolOpFunction;
119 typedef std::function<void(size_t, size_t, svl::SharedString)> StringOpFunction;
120 typedef std::function<void(size_t, size_t)> EmptyOpFunction;
121 typedef std::function<double(double, double)> CalculateOpFunction;
124 * When adding all numerical matrix elements for a scalar result such as
125 * summation, the interpreter wants to separate the first non-zero value
126 * with the rest of the summed values. This is necessary for better
127 * numerical stability, unless we sort all by absolute values before
128 * summing (not really an option) or use another algorithm, e.g. Kahan's
129 * summation algorithm,
130 * https://en.wikipedia.org/wiki/Kahan_summation_algorithm
132 template<typename tRes>
133 struct IterateResultMultiple
135 std::vector<tRes> maAccumulator;
136 size_t mnCount;
138 IterateResultMultiple(size_t nCount) :
139 maAccumulator(0), mnCount(nCount) {}
141 typedef IterateResultMultiple<KahanSum> KahanIterateResultMultiple;
142 typedef IterateResultMultiple<double> DoubleIterateResultMultiple;
145 * Iterator for executing one operation with the matrix data.
147 template<typename tRes>
148 struct IterateResult
150 tRes maAccumulator;
151 size_t mnCount;
153 IterateResult(tRes fAccumulator, size_t nCount)
154 : maAccumulator(fAccumulator), mnCount(nCount) {}
156 typedef IterateResult<KahanSum> KahanIterateResult;
157 typedef IterateResult<double> DoubleIterateResult;
160 /** Checks nC or nR for zero and uses GetElementsMax() whether a matrix of
161 the size of nC*nR could be allocated. A zero size (both nC and nR zero)
162 matrix is allowed for later resize.
164 bool static IsSizeAllocatable( SCSIZE nC, SCSIZE nR );
166 /// Value or boolean.
167 static bool IsValueType( ScMatValType nType )
169 return nType <= ScMatValType::Boolean;
172 /// Boolean.
173 static bool IsBooleanType( ScMatValType nType )
175 return nType == ScMatValType::Boolean;
178 /// String, empty or empty path, but not value nor boolean.
179 static bool IsNonValueType( ScMatValType nType )
181 return bool(nType & ScMatValType::NonvalueMask);
184 /** String, but not empty or empty path or any other type.
185 Not named IsStringType to prevent confusion because previously
186 IsNonValueType was named IsStringType. */
187 static bool IsRealStringType( ScMatValType nType )
189 return (nType & ScMatValType::NonvalueMask) == ScMatValType::String;
192 /// Empty, but not empty path or any other type.
193 static bool IsEmptyType( ScMatValType nType )
195 return (nType & ScMatValType::NonvalueMask) == ScMatValType::Empty;
198 /// Empty path, but not empty or any other type.
199 static bool IsEmptyPathType( ScMatValType nType )
201 return (nType & ScMatValType::NonvalueMask) == ScMatValType::EmptyPath;
204 /** Clone the matrix. */
205 ScMatrix* Clone() const;
207 /** Clone the matrix if mbCloneIfConst (immutable) is set, otherwise
208 return _this_ matrix, to be assigned to a ScMatrixRef. */
209 ScMatrix* CloneIfConst();
211 /** Set the matrix to mutable for CloneIfConst(), only the interpreter
212 should do this and know the consequences. */
213 void SetMutable();
215 /** Set the matrix to immutable for CloneIfConst(), only the interpreter
216 should do this and know the consequences. */
217 void SetImmutable() const;
220 * Resize the matrix to specified new dimension.
222 SC_DLLPUBLIC void Resize(SCSIZE nC, SCSIZE nR);
224 void Resize(SCSIZE nC, SCSIZE nR, double fVal);
226 /** Clone the matrix and extend it to the new size. nNewCols and nNewRows
227 MUST be at least of the size of the original matrix. */
228 ScMatrix* CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const;
230 SC_DLLPUBLIC void IncRef() const;
231 SC_DLLPUBLIC void DecRef() const;
233 void SetErrorInterpreter( ScInterpreter* p);
234 SC_DLLPUBLIC void GetDimensions( SCSIZE& rC, SCSIZE& rR) const;
235 SCSIZE GetElementCount() const;
236 bool ValidColRow( SCSIZE nC, SCSIZE nR) const;
238 /** For a row vector or column vector, if the position does not point into
239 the vector but is a valid column or row offset it is adapted such that
240 it points to an element to be replicated, same column row 0 for a row
241 vector, same row column 0 for a column vector. Else, for a 2D matrix,
242 returns false.
244 bool ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const;
246 /** Checks if the matrix position is within the matrix. If it is not, for a
247 row vector or column vector the position is adapted such that it points
248 to an element to be replicated, same column row 0 for a row vector,
249 same row column 0 for a column vector. Else, for a 2D matrix and
250 position not within matrix, returns false.
252 bool ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const;
254 SC_DLLPUBLIC void PutDouble( double fVal, SCSIZE nC, SCSIZE nR);
255 void PutDouble( double fVal, SCSIZE nIndex);
256 void PutDoubleTrans( double fVal, SCSIZE nIndex);
257 void PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR);
259 SC_DLLPUBLIC void PutString( const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR) ;
260 void PutString( const svl::SharedString& rStr, SCSIZE nIndex) ;
261 void PutStringTrans( const svl::SharedString& rStr, SCSIZE nIndex) ;
262 void PutString( const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR) ;
264 SC_DLLPUBLIC void PutEmpty( SCSIZE nC, SCSIZE nR);
265 void PutEmpty(SCSIZE nIndex);
266 void PutEmptyTrans( SCSIZE nIndex );
268 /// Jump sal_False without path
269 void PutEmptyPath( SCSIZE nC, SCSIZE nR) ;
270 SC_DLLPUBLIC void PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR ) ;
271 SC_DLLPUBLIC void PutBoolean( bool bVal, SCSIZE nC, SCSIZE nR) ;
273 void FillDouble( double fVal,
274 SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 ) ;
276 /** Put a column vector of doubles, starting at row nR, must fit into dimensions. */
277 void PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR ) ;
279 /** Put a column vector of strings, starting at row nR, must fit into dimensions. */
280 void PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR ) ;
282 /** Put a column vector of empties, starting at row nR, must fit into dimensions. */
283 void PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR ) ;
285 /** Put a column vector of empty results, starting at row nR, must fit into dimensions. */
286 void PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR ) ;
288 /** Put a column vector of empty paths, starting at row nR, must fit into dimensions. */
289 void PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR ) ;
291 /** May be used before obtaining the double value of an element to avoid
292 passing its NAN around.
293 @ATTENTION: MUST NOT be used if the element is a string!
294 Use GetErrorIfNotString() instead if not sure.
295 @returns 0 if no error, else one of err... constants */
296 FormulaError GetError( SCSIZE nC, SCSIZE nR) const ;
298 /** Use in ScInterpreter to obtain the error code, if any.
299 @returns 0 if no error or string element, else one of err... constants */
300 FormulaError GetErrorIfNotString( SCSIZE nC, SCSIZE nR) const
301 { return IsValue( nC, nR) ? GetError( nC, nR) : FormulaError::NONE; }
303 /// @return 0.0 if empty or empty path, else value or DoubleError.
304 double GetDouble( SCSIZE nC, SCSIZE nR) const ;
305 /// @return 0.0 if empty or empty path, else value or DoubleError.
306 double GetDouble( SCSIZE nIndex) const ;
307 /// @return value or DoubleError or string converted to value.
308 double GetDoubleWithStringConversion( SCSIZE nC, SCSIZE nR ) const ;
310 /// @return empty string if empty or empty path, else string content.
311 svl::SharedString GetString( SCSIZE nC, SCSIZE nR) const ;
312 /// @return empty string if empty or empty path, else string content.
313 svl::SharedString GetString( SCSIZE nIndex) const ;
315 /** @returns the matrix element's string if one is present, otherwise the
316 numerical value formatted as string, or in case of an error the error
317 string is returned; an empty string for empty, a "FALSE" string for
318 empty path. */
319 svl::SharedString GetString( ScInterpreterContext& rContext, SCSIZE nC, SCSIZE nR) const ;
321 /// @ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate
322 /// an empty string!
323 SC_DLLPUBLIC ScMatrixValue Get( SCSIZE nC, SCSIZE nR) const ;
325 /** @return <TRUE/> if string or any empty, empty cell, empty result, empty
326 path, in fact non-value. */
327 bool IsStringOrEmpty( SCSIZE nIndex ) const ;
329 /** @return <TRUE/> if string or any empty, empty cell, empty result, empty
330 path, in fact non-value. */
331 bool IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const ;
333 /// @return <TRUE/> if empty or empty cell or empty result, not empty path.
334 bool IsEmpty( SCSIZE nC, SCSIZE nR ) const ;
336 /// @return <TRUE/> if empty cell, not empty or empty result or empty path.
337 bool IsEmptyCell( SCSIZE nC, SCSIZE nR ) const ;
339 /// @return <TRUE/> if empty result, not empty or empty cell or empty path.
340 bool IsEmptyResult( SCSIZE nC, SCSIZE nR ) const ;
342 /// @return <TRUE/> if empty path, not empty or empty cell or empty result.
343 bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const ;
345 /// @return <TRUE/> if value or boolean.
346 bool IsValue( SCSIZE nIndex ) const ;
348 /// @return <TRUE/> if value or boolean.
349 bool IsValue( SCSIZE nC, SCSIZE nR ) const ;
351 /// @return <TRUE/> if value or boolean or empty or empty path.
352 bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const ;
354 /// @return <TRUE/> if boolean.
355 bool IsBoolean( SCSIZE nC, SCSIZE nR ) const ;
357 /// @return <TRUE/> if entire matrix is numeric, including booleans, with no strings or empties
358 bool IsNumeric() const ;
360 void MatTrans( const ScMatrix& mRes) const ;
361 void MatCopy ( const ScMatrix& mRes) const ;
363 // Convert ScInterpreter::CompareMat values (-1,0,1) to boolean values
364 void CompareEqual() ;
365 void CompareNotEqual() ;
366 void CompareLess() ;
367 void CompareGreater() ;
368 void CompareLessEqual() ;
369 void CompareGreaterEqual() ;
371 double And() const ; // logical AND of all matrix values, or NAN
372 double Or() const ; // logical OR of all matrix values, or NAN
373 double Xor() const ; // logical XOR of all matrix values, or NAN
375 KahanIterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
376 KahanIterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
377 DoubleIterateResult Product( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
378 size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings = false) const ;
379 size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const ;
380 size_t MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const ;
382 double GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
383 double GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
384 double GetGcd() const ;
385 double GetLcm() const ;
387 ScMatrixRef CompareMatrix(
388 sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const ;
391 * Convert the content of matrix into a linear array of numeric values.
392 * String elements are mapped to NaN's and empty elements are mapped to
393 * either NaN or zero values.
395 * @param bEmptyAsZero if true empty elements are mapped to zero values,
396 * otherwise they become NaN values.
398 void GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero = true ) const ;
399 void MergeDoubleArrayMultiply( std::vector<double>& rArray ) const ;
401 void NotOp(const ScMatrix& rMat) ;
402 void NegOp(const ScMatrix& rMat) ;
403 void AddOp(double fVal, const ScMatrix& rMat) ;
404 void SubOp(bool bFlag, double fVal, const ScMatrix& rMat) ;
405 void MulOp(double fVal, const ScMatrix& rMat) ;
406 void DivOp(bool bFlag, double fVal, const ScMatrix& rMat) ;
407 void PowOp(bool bFlag, double fVal, const ScMatrix& rMat) ;
409 KahanIterateResultMultiple CollectKahan(const std::vector<sc::op::kOp>& aOp) ;
411 void ExecuteOperation(const std::pair<size_t, size_t>& rStartPos, const std::pair<size_t, size_t>& rEndPos,
412 DoubleOpFunction aDoubleFunc, BoolOpFunction aBoolFunc, StringOpFunction aStringFunc,
413 EmptyOpFunction aEmptyFunc) const ;
415 void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
416 ScInterpreterContext& rContext, svl::SharedStringPool& rPool) ;
418 /** Apply binary operation to values from two input matrices, storing result into this matrix. */
419 void ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
420 ScInterpreter* pInterpreter, const CalculateOpFunction& op);
422 #if DEBUG_MATRIX
423 void Dump() const;
424 #endif
427 inline void intrusive_ptr_add_ref(const ScMatrix* p)
429 p->IncRef();
432 inline void intrusive_ptr_release(const ScMatrix* p)
434 p->DecRef();
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */