CompositeFunction.cpp 25 KB
Newer Older
1
2
3
4
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/Exception.h"
5
6
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
7
#include "MantidAPI/IConstraint.h"
8

9
#include <boost/lexical_cast.hpp>
10
11
12
#include <boost/shared_array.hpp>
#include <sstream>
#include <iostream>
13
#include <algorithm>
14
15
16
17
18
19

namespace Mantid
{
namespace API
{

Peterson, Peter's avatar
Peterson, Peter committed
20
21
using std::size_t;

22
//DECLARE_FUNCTION(CompositeFunction)
23

24
25
/// Copy contructor
CompositeFunction::CompositeFunction(const CompositeFunction& f)
26
:m_nActive(f.m_nParams),m_nParams(f.m_nParams),m_iConstraintFunction(0)
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
  m_functions.assign(f.m_functions.begin(),f.m_functions.end());
  m_activeOffsets.assign(f.m_activeOffsets.begin(),f.m_activeOffsets.end());
  m_paramOffsets.assign(f.m_paramOffsets.begin(),f.m_paramOffsets.end());
}

///Assignment operator
CompositeFunction& CompositeFunction::operator=(const CompositeFunction& f)
{
  m_nActive = f.m_nActive;
  m_nParams = f.m_nParams;
  m_functions.assign(f.m_functions.begin(),f.m_functions.end());
  m_activeOffsets.assign(f.m_activeOffsets.begin(),f.m_activeOffsets.end());
  m_paramOffsets.assign(f.m_paramOffsets.begin(),f.m_paramOffsets.end());
41
  m_iConstraintFunction = f.m_iConstraintFunction;
42
43
44
45
46
47
  return *this;
}

///Destructor
CompositeFunction::~CompositeFunction()
{
Peterson, Peter's avatar
Peterson, Peter committed
48
  for(size_t i=0;i<nFunctions();i++)
49
50
51
52
53
54
55
56
57
    if (m_functions[i]) delete m_functions[i];
}


/// Function initialization. Declare function parameters in this method.
void CompositeFunction::init()
{
}

58
59
60
61
62
63
64
65
66
67
68
/** 
 * Writes itself into a string. Functions derived from CompositeFunction must
 * override this method with something like this:
 *   std::string NewFunction::asString()const
 *   {
 *      ostr << "composite=" << this->name() << ';';
 *      // write NewFunction's own attributes and parameters
 *      ostr << CompositeFunction::asString();
 *      // write NewFunction's own ties and constraints
 *      // ostr << ";constraints=(" << ... <<")";
 *   }
69
 * @return the string representation of the composite function
70
 */
71
72
73
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
Peterson, Peter's avatar
Peterson, Peter committed
74
  for(size_t i=0;i<nFunctions();i++)
75
  {
76
    IFitFunction* fun = getFunction(i);
77
78
    bool isComp = dynamic_cast<CompositeFunction*>(fun) != 0;
    if (isComp) ostr << '(';
79
    ostr << fun->asString();
80
    if (isComp) ostr << ')';
81
82
83
84
85
86
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
87
  for(int i=0;i<nParams();i++)
88
89
90
91
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
92
      IFitFunction* fun = getFunction(functionIndex(i));
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
      std::string tmp = tie->asString(fun);
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
111
112
113
114
  }
  return ostr.str();
}

115
/** Sets a new value to the i-th parameter.
116
117
118
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
119
 */
120
void CompositeFunction::setParameter(int i, const double& value, bool explicitlySet)
121
{
122
  int iFun = functionIndex(i);
123
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
124
125
}

126
127
128
129
130
131
132
133
134
135
/** Sets a new description to the i-th parameter.
 *  @param i :: The parameter index
 *  @param description :: The new description
 */
void CompositeFunction::setParameterDescription(size_t i, const std::string& description)
{
  int iFun = functionIndex(i);
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

136
/** Get the i-th parameter.
137
 *  @param i :: The parameter index
138
 *  @return value of the requested parameter
139
 */
140
double CompositeFunction::getParameter(int i)const
141
{
Peterson, Peter's avatar
Peterson, Peter committed
142
  size_t iFun = functionIndex(i);
143
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
144
145
}

146
147
/**
 * Sets a new value to a parameter by name.
148
149
150
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
151
152
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
153
{
154
  std::string pname;
155
  int index;
156
  parseName(name,index,pname);
157
158
159
160
161
162
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
  else
  {   
    getFunction(index)->setParameter(pname,value,explicitlySet);
  }
163
164
}

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
 * @param value :: The new description
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
  int index;
  parseName(name,index,pname);
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
  else
  {   
    getFunction(index)->setParameterDescription(pname,description);
  }
}

183
184
/**
 * Parameters by name.
185
 * @param name :: The name of the parameter.
186
 * @return value of the requested named parameter
187
 */
188
189
double CompositeFunction::getParameter(const std::string& name)const
{
190
  std::string pname;
191
  int index;
192
  parseName(name,index,pname);
193
194
195
196
197
198
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
  else
  {   
    return getFunction(index)->getParameter(pname);
  }
199
200
201
}

/// Total number of parameters
202
int CompositeFunction::nParams()const
203
204
205
206
{
  return m_nParams;
}

207
/**
208
 * 
209
 * @param name :: The name of a parameter
210
 * @return index of the requested named parameter
211
 */
212
int CompositeFunction::parameterIndex(const std::string& name)const
213
{
214
  std::string pname;
215
  int index;
216
  parseName(name,index,pname);
217
218
219
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");

220
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
221
222
}

Nick Draper's avatar
re #100    
Nick Draper committed
223
/// Returns the name of parameter
224
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
225
/// @return The name of the parameter
226
std::string CompositeFunction::parameterName(int i)const
227
{
228
  int iFun = functionIndex(i);
229
230
231
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
232
233
}

234
235
236
237
238
239
240
241
242
243
244
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
  int iFun = functionIndex(i);
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

245
/// Number of active (in terms of fitting) parameters
246
int CompositeFunction::nActive()const
247
248
249
250
251
{
  return m_nActive;
}

/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
252
double CompositeFunction::activeParameter(int i)const
253
{
254
  int iFun = functionIndexActive(i);
255
256
257
258
259
260
  return m_functions[ iFun ]->activeParameter(i - m_activeOffsets[iFun]);
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
void CompositeFunction::setActiveParameter(int i, double value)
{
261
  int iFun = functionIndexActive(i);
262
  m_functions[ iFun ]->setActiveParameter(i - m_activeOffsets[iFun],value);
263
264
265
266
267
268
269
270
271
}

/// Update parameters after a fitting iteration
void CompositeFunction::updateActive(const double* in)
{
  for(int iFun = 0; iFun < int(m_functions.size()); iFun++)
  {
    m_functions[ iFun ]->updateActive(in + m_activeOffsets[ iFun ]);
  }
272
  applyTies();
273
274
275
}

/// Returns "global" index of active parameter i
276
int CompositeFunction::indexOfActive(int i)const
277
{
278
  int iFun = functionIndexActive(i);
279
280
281
282
  return m_paramOffsets[ iFun ] + m_functions[ iFun ]->indexOfActive(i - m_activeOffsets[iFun]);
}

/// Returns the name of active parameter i
283
std::string CompositeFunction::nameOfActive(int i)const
284
{
285
  int iFun = functionIndexActive(i);
286
287
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_activeOffsets[iFun]);
288
289
290
291
292
293
294
295
296
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
  int iFun = functionIndexActive(i);
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_activeOffsets[iFun]);
297
  return ostr.str();
298
299
}

300
/**
301
 * query to see in the function is active
302
 * @param i :: The index of a declared parameter
303
 * @return true if parameter i is active
304
 */
305
bool CompositeFunction::isActive(int i)const
306
307
308
309
310
311
{
  int iFun = functionIndex(i);
  return m_functions[ iFun ]->isActive(i - m_paramOffsets[iFun]);
}

/**
312
 * @param i :: A declared parameter index to be removed from active
313
 */
314
void CompositeFunction::removeActive(int i)
315
{
316
  if (!isActive(i)) return;
317
318
  int iFun = functionIndex(i);
  int ia = m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
319
  m_IFitFunctionActive.erase(m_IFitFunctionActive.begin()+ia);
320
321
  m_functions[ iFun ]->removeActive(i - m_paramOffsets[iFun]);

322
  m_nActive--;
Peterson, Peter's avatar
Peterson, Peter committed
323
  for(size_t j=iFun+1;j<nFunctions();j++)
324
325
326
    m_activeOffsets[j] -= 1;
}

327
/** Makes a parameter active again. It doesn't change the parameter's tie.
328
 * @param i :: A declared parameter index to be restored to active
329
 */
330
void CompositeFunction::restoreActive(int i)
331
{
332
333
  int iFun = functionIndex(i);
  int ia = m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
334

335
  std::vector<int>::iterator itFun = 
336
    std::find_if(m_IFitFunctionActive.begin(),m_IFitFunctionActive.end(),std::bind2nd(std::greater<int>(),i));
337

338
  m_IFitFunctionActive.insert(itFun,1,ia);
339
340
341
  m_functions[ iFun ]->restoreActive(i - m_paramOffsets[iFun]);

  m_nActive++;
Peterson, Peter's avatar
Peterson, Peter committed
342
  for(size_t j=iFun+1;j<nFunctions();j++)
343
344
345
    m_activeOffsets[j] += 1;
}

346
/**
347
 * @param i :: The index of a declared parameter
348
349
350
 * @return The index of declared parameter i in the list of active parameters or -1
 *         if the parameter is tied.
 */
351
int CompositeFunction::activeIndex(int i)const
352
{
353
354
  int iFun = functionIndex(i);
  int j = m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
355
356
357
358
359
360
361

  if (j == -1) 
  {
    return -1;
  }

  return m_activeOffsets[iFun] + j;
362
363
}

364
365
366
367
368
369
370
371
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_nActive = 0;
  m_paramOffsets.clear();
  m_activeOffsets.clear();
372
373
  m_IFitFunction.clear();
  m_IFitFunctionActive.clear();
374

375
  std::vector<IFitFunction*> functions(m_functions.begin(),m_functions.end());
376
377
  m_functions.clear();

378
  for(std::vector<IFitFunction*>::size_type i=0;i<functions.size();i++)
379
  {
380
    IFitFunction* f = functions[i];
381
382
    CompositeFunction* cf = dynamic_cast<CompositeFunction*>(f);
    if (cf) cf->checkFunction();
383
384
385
386
    addFunction(f);
  }
}

387
/** Add a function
388
 * @param f :: A pointer to the added function
389
 * @return The function index
390
 */
391
int CompositeFunction::addFunction(IFitFunction* f)
392
{
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
393
394
  m_IFitFunction.insert(m_IFitFunction.end(),f->nParams(), static_cast<int>(m_functions.size()));
  m_IFitFunctionActive.insert(m_IFitFunctionActive.end(),f->nActive(),static_cast<int>(m_functions.size()));
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  m_functions.push_back(f);
  //?f->init();
  if (m_paramOffsets.size() == 0)
  {
    m_paramOffsets.push_back(0);
    m_activeOffsets.push_back(0);
    m_nParams = f->nParams();
    m_nActive = f->nActive();
  }
  else
  {
    m_paramOffsets.push_back(m_nParams);
    m_activeOffsets.push_back(m_nActive);
    m_nParams += f->nParams();
    m_nActive += f->nActive();
  }
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
411
  return static_cast<int>(m_functions.size())-1;
412
413
}

414
/** Remove a function
415
416
 * @param i :: The index of the function to remove
 * @param del :: The deletion flag. If true the function will be deleted otherwise - simply detached
417
 */
418
void CompositeFunction::removeFunction(int i, bool del)
419
{
Peterson, Peter's avatar
Peterson, Peter committed
420
  if ( i >= static_cast<int>(nFunctions()) )
421
422
    throw std::out_of_range("Function index out of range.");

423
  IFitFunction* fun = getFunction(i);
424

425
426
  int dna = fun->nActive();
  int dnp = fun->nParams();
427

428
  for(int j=0;j<nParams();)
429
430
  {
    ParameterTie* tie = getTie(j);
431
    if (tie && tie->findParametersOf(fun))
432
433
434
435
436
437
438
439
440
441
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

  // Shift down the function indeces for parameters
442
  for(std::vector<int>::iterator it=m_IFitFunction.begin();it!=m_IFitFunction.end();)
443
  {
444

445
446
    if (*it == i)
    {
447
      it = m_IFitFunction.erase(it);
448
    }
449
    else
450
    {
451
452
453
454
455
      if (*it > i)
      {
        *it -= 1;
      }
      it++;
456
457
458
459
    }
  }

  // Shift down the function indeces for active parameters
460
  for(std::vector<int>::iterator it=m_IFitFunctionActive.begin();it!=m_IFitFunctionActive.end();)
461
462
463
  {
    if (*it == i)
    {
464
      it = m_IFitFunctionActive.erase(it);
465
    }
466
    else
467
    {
468
469
470
471
472
      if (*it > i)
      {
        *it -= 1;
      }
      it++;
473
474
475
476
477
    }
  }

  m_nActive -= dna;
  // Shift the active offsets down by the number of i-th function's active params
Peterson, Peter's avatar
Peterson, Peter committed
478
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
479
480
481
482
483
484
485
  {
    m_activeOffsets[j] -= dna;
  }
  m_activeOffsets.erase(m_activeOffsets.begin()+i);

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
Peterson, Peter's avatar
Peterson, Peter committed
486
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
487
488
489
490
491
492
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

  m_functions.erase(m_functions.begin()+i);
493
494
495
496
  if (del)
  {
    delete fun;
  }
497
498
}

499
/** Replace a function with a new one. The old function is deleted.
500
 *  The new function must have already its workspace set.
501
 * @param f_old :: The pointer to the function to replace. If it's not
502
 *  a member of this composite function nothing happens
503
 * @param f_new :: A pointer to the new function
504
 */
505
void CompositeFunction::replaceFunction(const IFitFunction* f_old,IFitFunction* f_new)
506
{
507
  std::vector<IFitFunction*>::const_iterator it = 
508
509
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
510
511
  std::vector<IFitFunction*>::difference_type iFun = it - m_functions.begin();
  replaceFunction(static_cast<int>(iFun),f_new);
512
513
}

514
/** Replace a function with a new one. The old function is deleted.
515
516
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
517
 */
518
void CompositeFunction::replaceFunction(int i,IFitFunction* f)
519
{
Peterson, Peter's avatar
Peterson, Peter committed
520
  if ( i >= static_cast<int>(nFunctions()) )
521
522
    throw std::out_of_range("Function index out of range.");

523
  IFitFunction* fun = getFunction(i);
524
525
  int na_old = fun->nActive();
  int np_old = fun->nParams();
526

527
528
  int na_new = f->nActive();
  int np_new = f->nParams();
529
530
531

  // Modify function indeces: The new function may have different number of parameters
  {
532
    std::vector<int>::iterator itFun = std::find(m_IFitFunction.begin(),m_IFitFunction.end(),i);
533
    if(itFun != m_IFitFunction.end()) // functions must have at least 1 parameter
534
    {
535
536
      if (np_old > np_new)
      {
537
        m_IFitFunction.erase(itFun,itFun + np_old - np_new);
538
539
540
      }
      else if (np_old < np_new) 
      {
541
        m_IFitFunction.insert(itFun,np_new - np_old,i);
542
      }
543
    }
544
545
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
546
547
      itFun = std::find_if(m_IFitFunction.begin(),m_IFitFunction.end(),std::bind2nd(std::greater<int>(),i));
      m_IFitFunction.insert(itFun,np_new,i);
548
    }
549
550
551
552
  }

  // Modify function indeces: The new function may have different number of active parameters
  {
553
    std::vector<int>::iterator itFun = std::find(m_IFitFunctionActive.begin(),m_IFitFunctionActive.end(),i);
554
    if (itFun != m_IFitFunctionActive.end())
555
556
557
    {
      if (na_old > na_new)
      {
558
        m_IFitFunctionActive.erase(itFun,itFun + na_old - na_new);
559
560
561
      }
      else if (na_old < na_new) 
      {
562
        m_IFitFunctionActive.insert(itFun,na_new - na_old,i);
563
564
565
566
      }
    }
    else if (na_new > 0)
    {
567
568
      itFun = std::find_if(m_IFitFunctionActive.begin(),m_IFitFunctionActive.end(),std::bind2nd(std::greater<int>(),i));
      m_IFitFunctionActive.insert(itFun,na_new,i);
569
570
571
    }
  }

572
  int dna = na_new - na_old;
573
574
  m_nActive += dna;
  // Recalc the active offsets 
Peterson, Peter's avatar
Peterson, Peter committed
575
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
576
577
578
579
  {
    m_activeOffsets[j] += dna;
  }

580
  int dnp = np_new - np_old;
581
582
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
Peterson, Peter's avatar
Peterson, Peter committed
583
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
584
585
586
587
588
589
590
591
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
  delete fun;
}

592
/**
593
 * @param i :: The index of the function
594
 * @return function at the requested index
595
 */
Peterson, Peter's avatar
Peterson, Peter committed
596
IFitFunction* CompositeFunction::getFunction(size_t i)const
597
{
Peterson, Peter's avatar
Peterson, Peter committed
598
  if ( i >= nFunctions() )
599
  {
600
    throw std::out_of_range("Function index out of range.");
601
  }
602
603
604
  return m_functions[i];
}

605
606
/**
 * Get the index of the function to which parameter i belongs
607
 * @param i :: The parameter index
608
 * @return function index of the requested parameter
609
 */
Peterson, Peter's avatar
Peterson, Peter committed
610
size_t CompositeFunction::functionIndex(size_t i)const
611
{
612
613
614
615
616
  // Casting this to an int could result in it being turned into a -1
  // so need to check that also. 
  // @todo: nParams should return size_t and get rid of -1 error returns
  int iindex = static_cast<int>(i);
  if( iindex >= nParams() || iindex < 0 )
617
  {
618
    throw std::out_of_range("Function parameter index out of range.");
619
  }
620
  return m_IFitFunction[i];
621
622
623
624
}

/**
 * Get the index of the function to which parameter i belongs
625
 * @param i :: The active parameter index
626
 * @return active function index of the requested parameter
627
 */
Peterson, Peter's avatar
Peterson, Peter committed
628
size_t CompositeFunction::functionIndexActive(size_t i)const
629
{
630
631
632
633
634
  // Casting this to an int could result in it being turned into a -1
  // so need to check that also. 
  // @todo: nParams should return size_t and get rid of -1 error returns
  int iindex = static_cast<int>(i);
  if( iindex >= nParams() || iindex < 0 )
635
    throw std::out_of_range("Function parameter index out of range.");
636
  return m_IFitFunctionActive[i];
637
638
639
}

/**
640
641
642
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
* @param index :: Receives function index or -1 
* @param name :: Receives the parameter name
643
*/
644
void CompositeFunction::parseName(const std::string& varName,int& index, std::string& name)
645
{
646
647
648
649
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
    name = varName;
650
651
    index = -1;
    return;
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

    std::string sindex = varName.substr(1,i-1);
    index = boost::lexical_cast<int>(sindex);

    if (i == varName.size() - 1)
      throw std::invalid_argument("Name cannot be empty");

    name = varName.substr(i+1);
  }
666
667
}

668
/** Returns the index of parameter i as it declared in its function
669
 * @param i :: The parameter index
670
671
 * @return The local index of the parameter
 */
672
int CompositeFunction::parameterLocalIndex(int i)const
673
674
675
676
677
{
  int iFun = functionIndex(i);
  return i - m_paramOffsets[iFun];
}

678
/** Returns the name of parameter i as it declared in its function
679
 * @param i :: The parameter index
680
681
 * @return The pure parameter name (without the function identifier f#.)
 */
682
std::string CompositeFunction::parameterLocalName(int i)const
683
684
685
686
687
{
  int iFun = functionIndex(i);
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

Janik Zikovsky's avatar
Janik Zikovsky committed
688
689
690
691
692
693
// /** Initialize the function providing it the workspace
// * @param workspace :: The shared pointer to a workspace to which the function will be fitted
// * @param spec :: The number of a spectrum for fitting
// * @param xMin :: The minimum bin index of spectrum spec that will be used in fitting
// * @param xMax :: The maximum bin index of spectrum spec that will be used in fitting
// */
694
695
696
697
698
699
700
701
//void CompositeFunction::setMatrixWorkspace(boost::shared_ptr<const API::MatrixWorkspace> workspace,int spec,int xMin,int xMax)
//{
//  IFitFunction::setMatrixWorkspace(workspace,spec,xMin,xMax);
//  for(int i=0;i<nFunctions();i++)
//  {
//    getFunction(i)->setMatrixWorkspace(workspace,spec,xMin,xMax);
//  }
//}
702

703
/**
704
 * Apply the ties.
705
706
707
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
708
  for(size_t i=0;i<nFunctions();i++)
709
710
711
712
713
714
715
716
717
718
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
719
  for(size_t i=0;i<nFunctions();i++)
720
721
722
723
724
725
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
726
 * @param i :: The index of the tied parameter.
727
728
 * @return True if successfull
 */
729
bool CompositeFunction::removeTie(int i)
730
{
731
  int iFun = functionIndex(i);
732
733
734
735
736
737
738
739
740
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  if (res)
  {
    m_nActive++;
  }
  return res;
}

/** Get the tie of i-th parameter
741
 * @param i :: The parameter index
742
 * @return A pointer to the tie.
743
 */
744
ParameterTie* CompositeFunction::getTie(int i)const
745
746
747
748
749
750
751
{
  int iFun = functionIndex(i);
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
752
 * @param tie :: A pointer to a new tie
753
754
755
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
756
  int i = getParameterIndex(*tie);
757
758
759
760
761
762
763
764
765
766
  if (i < 0)
  {
    throw std::logic_error("Trying to use a tie on a parameter not belonging to this function");
  }
  int iFun = functionIndex(i);
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
767
768
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
769
 */
770
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
771
{
772
773
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
774
  (void) description; //Avoid compiler warning
775
776
777
778
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
779
 *  @param ic :: Pointer to a constraint.
780
781
782
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
783
784
785
  int i = getParameterIndex(*ic);
  int iFun = functionIndex(i);
  getFunction(iFun)->addConstraint(ic);
786
787
}

788
789
void CompositeFunction::setParametersToSatisfyConstraints()
{
Peterson, Peter's avatar
Peterson, Peter committed
790
  for(size_t i=0;i<nFunctions();i++)
791
792
793
794
795
  {
    getFunction(i)->setParametersToSatisfyConstraints();
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
796
/// Get constraint
797
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
798
/// @return A pointer to the constraint
799
IConstraint* CompositeFunction::getConstraint(int i)const
800
{
801
  int iFun = functionIndex(i);
802
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
803
804
}

805
/** Remove a constraint
806
 * @param parName :: The name of a parameter which constarint to remove.
807
808
809
810
811
812
813
814
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
  int iPar = parameterIndex(parName);
  int iFun = functionIndex(iPar);
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

815
/** Checks if a constraint has been explicitly set
816
 *  @param i :: The parameter index
817
 *  @return true if the function is explicitly set
818
 */
819
bool CompositeFunction::isExplicitlySet(int i)const
820
{
821
  int iFun = functionIndex(i);
822
823
824
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

825
826
/**
 * Returns the index of parameter if the ref points to one of the member function or -1
827
 * @param ref :: A reference to a parameter
828
829
 * @return Parameter index or -1
 */
830
int CompositeFunction::getParameterIndex(const ParameterReference& ref)const
831
{
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
832
  if (ref.getFunction() == this && static_cast<int>(ref.getIndex()) < nParams())
833
  {
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
834
    return static_cast<int>(ref.getIndex());
835
  }
Peterson, Peter's avatar
Peterson, Peter committed
836
  for(size_t iFun=0;iFun<nFunctions();iFun++)
837
  {
838
    int iLocalIndex = getFunction(iFun)->getParameterIndex(ref);
839
840
841
842
843
    if (iLocalIndex >= 0)
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
844
845
846
  return -1;
}

847
/**
848
 * @param ref :: The reference
849
850
 * @return A function containing parameter pointed to by ref
 */
851
IFitFunction* CompositeFunction::getContainingFunction(const ParameterReference& ref)const
852
{
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
853
  if (ref.getFunction() == this && static_cast<int>(ref.getIndex()) < nParams())
854
855
856
  {
    return ref.getFunction();
  }
Peterson, Peter's avatar
Peterson, Peter committed
857
  for(size_t iFun=0;iFun<nFunctions();iFun++)
858
  {
859
    IFitFunction* fun = static_cast<IFitFunction*>(getFunction(iFun)->getContainingFunction(ref));
860
861
862
863
864
865
866
    if (fun)
    {
      return getFunction(iFun);
    }
  }
  return NULL;
}
867

868
/**
869
 * @param fun :: The searched function
870
871
 * @return A function containing the argument function fun
 */
872
IFitFunction* CompositeFunction::getContainingFunction(const IFitFunction* fun)
873
874
875
876
877
{
  if (fun == this)
  {
    return this;
  }
Peterson, Peter's avatar
Peterson, Peter committed
878
  for(size_t iFun=0;iFun<nFunctions();iFun++)
879
  {
880
    IFitFunction* f = static_cast<IFitFunction*>(getFunction(iFun)->getContainingFunction(fun));
881
882
883
884
885
886
887
888
    if (f)
    {
      return getFunction(iFun);
    }
  }
  return NULL;
}

889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
//void CompositeFunction::setWorkspace(boost::shared_ptr<Workspace> ws,const std::string& slicing)
//{
//  IFitFunction::setWorkspace(ws,slicing);
//  for(int iFun=0;iFun<nFunctions();iFun++)
//  {
//    getFunction(iFun)->setUpNewStuff(m_xValues,m_weights);
//  }
//}

//void CompositeFunction::setUpNewStuff(boost::shared_array<double> xs,boost::shared_array<double> weights)
//{
//  IFitFunction::setUpNewStuff(xs,weights);
//  for(int iFun=0;iFun<nFunctions();iFun++)
//  {
//    getFunction(iFun)->setUpNewStuff(xs,weights);
//  }
//}
906

907
908
} // namespace API
} // namespace Mantid