CompositeFunction.cpp 23 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
#include "MantidAPI/FunctionFactory.h"
9

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

namespace Mantid
{
namespace API
{

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

23
DECLARE_FUNCTION(CompositeFunction)
24

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

///Assignment operator
CompositeFunction& CompositeFunction::operator=(const CompositeFunction& f)
{
39
  //m_nActive = f.m_nActive;
40
41
  m_nParams = f.m_nParams;
  m_functions.assign(f.m_functions.begin(),f.m_functions.end());
42
  //m_activeOffsets.assign(f.m_activeOffsets.begin(),f.m_activeOffsets.end());
43
  m_paramOffsets.assign(f.m_paramOffsets.begin(),f.m_paramOffsets.end());
44
  m_iConstraintFunction = f.m_iConstraintFunction;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  return *this;
}

///Destructor
CompositeFunction::~CompositeFunction()
{
}


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

59
60
61
62
63
64
65
66
67
68
69
/** 
 * 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=(" << ... <<")";
 *   }
70
 * @return the string representation of the composite function
71
 */
72
73
74
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
75
  if (name() != "CompositeFunction")
76
77
78
  {
    ostr << "composite=" <<name() << ";";
  }
Peterson, Peter's avatar
Peterson, Peter committed
79
  for(size_t i=0;i<nFunctions();i++)
80
  {
81
82
    IFunction_sptr fun = getFunction(i);
    bool isComp = boost::dynamic_pointer_cast<CompositeFunction>(fun) != 0;
83
    if (isComp) ostr << '(';
84
    ostr << fun->asString();
85
    if (isComp) ostr << ')';
86
87
88
89
90
91
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
92
  for(size_t i=0;i<nParams();i++)
93
94
95
96
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
97
98
      IFunction_sptr fun = getFunction(functionIndex(i));
      std::string tmp = tie->asString(fun.get());
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
116
117
118
119
  }
  return ostr.str();
}

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/** Function you want to fit to. 
 *  @param domain :: The buffer for writing the calculated values. Must be big enough to accept dataSize() values
 */
void CompositeFunction::function(const FunctionDomain& domain, FunctionValues& values)const
{
  FunctionValues tmp(domain);
  for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
  {
    domain.reset();
    m_functions[ iFun ]->function(domain,tmp);
    values += tmp;
  }
}

/**
 * Derivatives of function with respect to active parameters
 * @param domain :: Function domain to get the arguments from.
 * @param jacobian :: A Jacobian to store the derivatives.
 */
void CompositeFunction::functionDeriv(const FunctionDomain& domain, Jacobian& jacobian)
{
  for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
  {
    domain.reset();
144
    PartialJacobian J(&jacobian,paramOffset(iFun));
145
146
147
148
    getFunction(iFun)->functionDeriv(domain,J);
  }
}

149
/** Sets a new value to the i-th parameter.
150
151
152
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
153
 */
154
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
155
{
156
  size_t iFun = functionIndex(i);
157
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
158
159
}

160
161
162
163
164
165
/** 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)
{
166
  size_t iFun = functionIndex(i);
167
168
169
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

170
/** Get the i-th parameter.
171
 *  @param i :: The parameter index
172
 *  @return value of the requested parameter
173
 */
174
double CompositeFunction::getParameter(size_t i)const
175
{
Peterson, Peter's avatar
Peterson, Peter committed
176
  size_t iFun = functionIndex(i);
177
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
178
179
}

180
181
/**
 * Sets a new value to a parameter by name.
182
183
184
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
185
186
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
187
{
188
  std::string pname;
189
  size_t index;
190
  parseName(name,index,pname);
191
  getFunction(index)->setParameter(pname,value,explicitlySet);
192
193
}

194
195
196
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
197
 * @param description :: The new description
198
199
200
201
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
202
  size_t index;
203
  parseName(name,index,pname);
204
  getFunction(index)->setParameterDescription(pname,description);
205
206
}

207
208
/**
 * Parameters by name.
209
 * @param name :: The name of the parameter.
210
 * @return value of the requested named parameter
211
 */
212
213
double CompositeFunction::getParameter(const std::string& name)const
{
214
  std::string pname;
215
  size_t index;
216
  parseName(name,index,pname);
217
  return getFunction(index)->getParameter(pname);
218
219
220
}

/// Total number of parameters
221
size_t CompositeFunction::nParams()const
222
223
224
225
{
  return m_nParams;
}

226
/**
227
 * 
228
 * @param name :: The name of a parameter
229
 * @return index of the requested named parameter
230
 */
231
size_t CompositeFunction::parameterIndex(const std::string& name)const
232
{
233
  std::string pname;
234
  size_t index;
235
  parseName(name,index,pname);
236
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
237
238
}

Nick Draper's avatar
re #100    
Nick Draper committed
239
/// Returns the name of parameter
240
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
241
/// @return The name of the parameter
242
std::string CompositeFunction::parameterName(size_t i)const
243
{
244
  size_t iFun = functionIndex(i);
245
246
247
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
248
249
}

250
251
252
253
254
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
255
  size_t iFun = functionIndex(i);
256
257
258
259
260
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

261
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
262
double CompositeFunction::activeParameter(size_t i)const
263
{
264
265
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->activeParameter(i - m_paramOffsets[iFun]);
266
267
268
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
269
void CompositeFunction::setActiveParameter(size_t i, double value)
270
{
271
272
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setActiveParameter(i - m_paramOffsets[iFun],value);
273
274
275
}

/// Returns the name of active parameter i
276
std::string CompositeFunction::nameOfActive(size_t i)const
277
{
278
  size_t iFun = functionIndex(i);
279
  std::ostringstream ostr;
280
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_paramOffsets[iFun]);
281
282
283
284
285
286
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
287
  size_t iFun = functionIndex(i);
288
  std::ostringstream ostr;
289
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_paramOffsets[iFun]);
290
  return ostr.str();
291
292
}

293
294
295
296
297
298
299
300
301
302
303
/**
 * query to see in the function is active
 * @param i :: The index of a declared parameter
 * @return true if parameter i is active
 */
bool CompositeFunction::isActive(size_t i)const
{
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->isActive(i - m_paramOffsets[iFun]);
}

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

/**
316
 * @param i :: A declared parameter index to be removed from active
317
 */
318
void CompositeFunction::fix(size_t i)
319
{
320
  size_t iFun = functionIndex(i);
321
322
323
324
325
326
327
  //std::vector<size_t>::iterator ia = std::find(m_IFunctionActive.begin(),m_IFunctionActive.end(),iFun);
  //if (ia == m_IFunctionActive.end())
  //{// isFixed(i) should have returned true
  //  throw std::runtime_error("Inconsistency in CompositeFunction when fixing parameter "+
  //    boost::lexical_cast<std::string>(i));
  //}
  //m_IFunctionActive.erase(ia);
328
  m_functions[ iFun ]->fix(i - m_paramOffsets[iFun]);
329

330
331
332
  //m_nActive--;
  //for(size_t j=iFun+1;j<nFunctions();j++)
  //  m_activeOffsets[j] -= 1;
333
334
}

335
/** Makes a parameter active again. It doesn't change the parameter's tie.
336
 * @param i :: A declared parameter index to be restored to active
337
 */
338
void CompositeFunction::unfix(size_t i)
339
{
340
  size_t iFun = functionIndex(i);
341

342
  //m_IFunctionActive.insert(m_IFunctionActive.begin() + m_activeOffsets[iFun],iFun);
343
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
344

345
346
347
  //m_nActive++;
  //for(size_t j=iFun+1;j<nFunctions();j++)
  //  m_activeOffsets[j] += 1;
348
349
}

350
351
352
353
354
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
355
  //m_nActive = 0;
356
  m_paramOffsets.clear();
357
  //m_activeOffsets.clear();
358
  m_IFunction.clear();
359
  //m_IFunctionActive.clear();
360

361
  std::vector<IFunction_sptr> functions(m_functions.begin(),m_functions.end());
362
363
  m_functions.clear();

364
  for(std::vector<IFunction_sptr>::size_type i=0;i<functions.size();i++)
365
  {
366
367
    IFunction_sptr f = functions[i];
    CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f);
368
    if (cf) cf->checkFunction();
369
370
371
372
    addFunction(f);
  }
}

373
/** Add a function
374
 * @param f :: A pointer to the added function
375
 * @return The function index
376
 */
377
size_t CompositeFunction::addFunction(IFunction_sptr f)
378
{
379
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
380
  //m_IFunctionActive.insert(m_IFunctionActive.end(),f->nActive(),m_functions.size());
381
382
383
384
385
  m_functions.push_back(f);
  //?f->init();
  if (m_paramOffsets.size() == 0)
  {
    m_paramOffsets.push_back(0);
386
    //m_activeOffsets.push_back(0);
387
    m_nParams = f->nParams();
388
    //m_nActive = f->nActive();
389
390
391
392
  }
  else
  {
    m_paramOffsets.push_back(m_nParams);
393
    //m_activeOffsets.push_back(m_nActive);
394
    m_nParams += f->nParams();
395
    //m_nActive += f->nActive();
396
  }
397
  return m_functions.size() - 1;
398
399
}

400
/** Remove a function
401
402
 * @param i :: The index of the function to remove
 * @param del :: The deletion flag. If true the function will be deleted otherwise - simply detached
403
 */
404
void CompositeFunction::removeFunction(size_t i)
405
{
406
  if ( i >= nFunctions() )
407
408
    throw std::out_of_range("Function index out of range.");

409
  IFunction_sptr fun = getFunction(i);
410

411
  //size_t dna = fun->nActive();
412
  size_t dnp = fun->nParams();
413

414
  for(size_t j=0;j<nParams();)
415
416
  {
    ParameterTie* tie = getTie(j);
417
    if (tie && tie->findParametersOf(fun.get()))
418
419
420
421
422
423
424
425
426
427
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

  // Shift down the function indeces for parameters
428
  for(std::vector<size_t>::iterator it=m_IFunction.begin();it!=m_IFunction.end();)
429
  {
430

431
432
    if (*it == i)
    {
433
      it = m_IFunction.erase(it);
434
    }
435
    else
436
    {
437
438
439
440
      if (*it > i)
      {
        *it -= 1;
      }
441
      ++it;
442
443
444
445
    }
  }

  // Shift down the function indeces for active parameters
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
  //for(std::vector<size_t>::iterator it=m_IFunctionActive.begin();it!=m_IFunctionActive.end();)
  //{
  //  if (*it == i)
  //  {
  //    it = m_IFunctionActive.erase(it);
  //  }
  //  else
  //  {
  //    if (*it > i)
  //    {
  //      *it -= 1;
  //    }
  //    ++it;
  //  }
  //}

  //m_nActive -= dna;
  //// Shift the active offsets down by the number of i-th function's active params
  //for(size_t j=i+1;j<nFunctions();j++)
  //{
  //  m_activeOffsets[j] -= dna;
  //}
  //m_activeOffsets.erase(m_activeOffsets.begin()+i);
469
470
471

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
472
  for(size_t j=i+1;j<nFunctions();j++)
473
474
475
476
477
478
479
480
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

  m_functions.erase(m_functions.begin()+i);
}

481
/** Replace a function with a new one. The old function is deleted.
482
 *  The new function must have already its workspace set.
483
 * @param f_old :: The pointer to the function to replace. If it's not
484
 *  a member of this composite function nothing happens
485
 * @param f_new :: A pointer to the new function
486
 */
487
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
488
{
489
  std::vector<IFunction_sptr>::const_iterator it = 
490
491
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
492
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
493
  replaceFunction(iFun,f_new);
494
495
}

496
/** Replace a function with a new one. The old function is deleted.
497
498
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
499
 */
500
void CompositeFunction::replaceFunction(size_t i,IFunction_sptr f)
501
{
502
  if ( i >= nFunctions() )
503
504
    throw std::out_of_range("Function index out of range.");

505
  IFunction_sptr fun = getFunction(i);
506
  //size_t na_old = fun->nActive();
507
  size_t np_old = fun->nParams();
508

509
  //size_t na_new = f->nActive();
510
  size_t np_new = f->nParams();
511
512
513

  // Modify function indeces: The new function may have different number of parameters
  {
514
515
    std::vector<size_t>::iterator itFun = std::find(m_IFunction.begin(),m_IFunction.end(),i);
    if(itFun != m_IFunction.end()) // functions must have at least 1 parameter
516
    {
517
518
      if (np_old > np_new)
      {
519
        m_IFunction.erase(itFun,itFun + np_old - np_new);
520
521
522
      }
      else if (np_old < np_new) 
      {
523
        m_IFunction.insert(itFun,np_new - np_old,i);
524
      }
525
    }
526
527
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
528
529
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
530
    }
531
532
533
  }

  // Modify function indeces: The new function may have different number of active parameters
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  //{
  //  std::vector<size_t>::iterator itFun = std::find(m_IFunctionActive.begin(),m_IFunctionActive.end(),i);
  //  if (itFun != m_IFunctionActive.end())
  //  {
  //    if (na_old > na_new)
  //    {
  //      m_IFunctionActive.erase(itFun,itFun + na_old - na_new);
  //    }
  //    else if (na_old < na_new) 
  //    {
  //      m_IFunctionActive.insert(itFun,na_new - na_old,i);
  //    }
  //  }
  //  else if (na_new > 0)
  //  {
  //    itFun = std::find_if(m_IFunctionActive.begin(),m_IFunctionActive.end(),std::bind2nd(std::greater<size_t>(),i));
  //    m_IFunctionActive.insert(itFun,na_new,i);
  //  }
  //}

  //size_t dna = na_new - na_old;
  //m_nActive += dna;
  //// Recalc the active offsets 
  //for(size_t j=i+1;j<nFunctions();j++)
  //{
  //  m_activeOffsets[j] += dna;
  //}
561

562
  size_t dnp = np_new - np_old;
563
564
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
565
  for(size_t j=i+1;j<nFunctions();j++)
566
567
568
569
570
571
572
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
}

573
/**
574
 * @param i :: The index of the function
575
 * @return function at the requested index
576
 */
577
IFunction_sptr CompositeFunction::getFunction(std::size_t i)const
578
{
Peterson, Peter's avatar
Peterson, Peter committed
579
  if ( i >= nFunctions() )
580
  {
581
    throw std::out_of_range("Function index out of range.");
582
  }
583
584
585
  return m_functions[i];
}

586
587
/**
 * Get the index of the function to which parameter i belongs
588
 * @param i :: The parameter index
589
 * @return function index of the requested parameter
590
 */
591
size_t CompositeFunction::functionIndex(std::size_t i)const
592
{
593
  if( i >= nParams() )
594
  {
595
    throw std::out_of_range("Function parameter index out of range.");
596
  }
597
  return m_IFunction[i];
598
599
600
601
}

/**
 * Get the index of the function to which parameter i belongs
602
 * @param i :: The active parameter index
603
 * @return active function index of the requested parameter
604
 */
605
606
607
608
609
610
//size_t CompositeFunction::functionIndexActive(std::size_t i)const
//{
//  if( i >= nParams() )
//    throw std::out_of_range("Function parameter index out of range.");
//  return m_IFunctionActive[i];
//}
611
612

/**
613
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
614
* @param index :: Receives function index or throws std::invalid_argument
615
* @param name :: Receives the parameter name
616
*/
617
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
618
{
619
620
621
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
622
    throw std::invalid_argument("Parameter " + varName + " not found.");
623
624
625
626
627
628
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

629
    std::string sindex = varName.substr(1,i - 1);
630
631
632
633
634
635
636
    index = boost::lexical_cast<int>(sindex);

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

    name = varName.substr(i+1);
  }
637
638
}

639
/** Returns the index of parameter i as it declared in its function
640
 * @param i :: The parameter index
641
642
 * @return The local index of the parameter
 */
643
size_t CompositeFunction::parameterLocalIndex(size_t i)const
644
{
645
  size_t iFun = functionIndex(i);
646
647
648
  return i - m_paramOffsets[iFun];
}

649
/** Returns the name of parameter i as it declared in its function
650
 * @param i :: The parameter index
651
652
 * @return The pure parameter name (without the function identifier f#.)
 */
653
std::string CompositeFunction::parameterLocalName(size_t i)const
654
{
655
  size_t iFun = functionIndex(i);
656
657
658
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

659
/**
660
 * Apply the ties.
661
662
663
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
664
  for(size_t i=0;i<nFunctions();i++)
665
666
667
668
669
670
671
672
673
674
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
675
  for(size_t i=0;i<nFunctions();i++)
676
677
678
679
680
681
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
682
 * @param i :: The index of the tied parameter.
683
684
 * @return True if successfull
 */
685
bool CompositeFunction::removeTie(size_t i)
686
{
687
  size_t iFun = functionIndex(i);
688
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
689
690
691
692
  //if (res)
  //{
  //  m_nActive++;
  //}
693
694
695
696
  return res;
}

/** Get the tie of i-th parameter
697
 * @param i :: The parameter index
698
 * @return A pointer to the tie.
699
 */
700
ParameterTie* CompositeFunction::getTie(size_t i)const
701
{
702
  size_t iFun = functionIndex(i);
703
704
705
706
707
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
708
 * @param tie :: A pointer to a new tie
709
710
711
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
712
713
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
714
715
716
717
718
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
719
720
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
721
 * @param description :: Parameter documentation
722
 */
723
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
724
{
725
726
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
727
  (void) description; //Avoid compiler warning
728
729
730
731
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
732
 *  @param ic :: Pointer to a constraint.
733
734
735
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
736
737
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
738
  getFunction(iFun)->addConstraint(ic);
739
740
}

741
742
void CompositeFunction::setParametersToSatisfyConstraints()
{
Peterson, Peter's avatar
Peterson, Peter committed
743
  for(size_t i=0;i<nFunctions();i++)
744
745
746
747
748
  {
    getFunction(i)->setParametersToSatisfyConstraints();
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
749
/// Get constraint
750
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
751
/// @return A pointer to the constraint
752
IConstraint* CompositeFunction::getConstraint(size_t i)const
753
{
754
  size_t iFun = functionIndex(i);
755
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
756
757
}

758
/** Remove a constraint
759
 * @param parName :: The name of a parameter which constarint to remove.
760
761
762
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
763
764
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
765
766
767
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

768
/** Checks if a constraint has been explicitly set
769
 *  @param i :: The parameter index
770
 *  @return true if the function is explicitly set
771
 */
772
bool CompositeFunction::isExplicitlySet(size_t i)const
773
{
774
  size_t iFun = functionIndex(i);
775
776
777
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

778
/**
779
 * Returns the index of parameter if the ref points to one of the member function
780
 * @param ref :: A reference to a parameter
781
 * @return Parameter index or number of nParams() if parameter not found
782
 */
783
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
784
{
785
  if (ref.getFunction() == this && ref.getIndex() < nParams())
786
  {
787
    return ref.getIndex();
788
  }
Peterson, Peter's avatar
Peterson, Peter committed
789
  for(size_t iFun=0;iFun<nFunctions();iFun++)
790
  {
791
    IFunction_sptr fun = getFunction(iFun);
792
793
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
794
795
796
797
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
798
  return nParams();
799
800
}

801
/**
802
 * Returns the shrared pointer to the function conataining a parameter
803
 * @param ref :: The reference
804
805
 * @return A function containing parameter pointed to by ref
 */
806
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
807
{
Peterson, Peter's avatar
Peterson, Peter committed
808
  for(size_t iFun=0;iFun<nFunctions();iFun++)
809
  {
810
811
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
812
    {
813
      return fun;
814
815
    }
  }
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  return IFunction_sptr();
}

///**
// * @param fun :: The searched function
// * @return A function containing the argument function fun
// */
//IFunction_sptr CompositeFunction::getContainingFunction(IFunction_sptr fun)
//{
//  if (fun.get() == this)
//  {
//    return fun;
//  }
//  for(size_t iFun=0;iFun<nFunctions();iFun++)
//  {
//    IFunction_sptr f = getFunction(iFun);
//    if (f == fun)
//    {
//      return getFunction(iFun);
//    }
//  }
//  return IFunction_sptr();
//}
839

840
841
} // namespace API
} // namespace Mantid