xref: /trunk/main/sccomp/source/solver/solver.cxx (revision e4f93722)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #undef LANGUAGE_NONE
25 #define WINAPI __stdcall
26 #define LoadInverseLib FALSE
27 #define LoadLanguageLib FALSE
28 #include <lpsolve/lp_lib.h>
29 #undef LANGUAGE_NONE
30 
31 #include "solver.hxx"
32 #include "solver.hrc"
33 
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/container/XIndexAccess.hpp>
36 #include <com/sun/star/frame/XModel.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
39 #include <com/sun/star/sheet/XSpreadsheet.hpp>
40 #include <com/sun/star/table/CellAddress.hpp>
41 #include <com/sun/star/table/CellRangeAddress.hpp>
42 #include <com/sun/star/text/XTextRange.hpp>
43 
44 #include <rtl/math.hxx>
45 #include <rtl/ustrbuf.hxx>
46 #include <cppuhelper/factory.hxx>
47 #include <vector>
48 #include <hash_map>
49 
50 #include <tools/resmgr.hxx>
51 
52 using namespace com::sun::star;
53 
54 using ::rtl::OUString;
55 
56 #define C2U(constAsciiStr) (::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( constAsciiStr ) ))
57 
58 #define STR_NONNEGATIVE   "NonNegative"
59 #define STR_INTEGER       "Integer"
60 #define STR_TIMEOUT       "Timeout"
61 #define STR_EPSILONLEVEL  "EpsilonLevel"
62 #define STR_LIMITBBDEPTH  "LimitBBDepth"
63 
64 // -----------------------------------------------------------------------
65 //  Resources from tools are used for translated strings
66 
67 static ResMgr* pSolverResMgr = NULL;
68 
69 OUString lcl_GetResourceString( sal_uInt32 nId )
70 {
71     if (!pSolverResMgr)
72         pSolverResMgr = CREATEVERSIONRESMGR( solver );
73 
74     return String( ResId( nId, *pSolverResMgr ) );
75 }
76 
77 // -----------------------------------------------------------------------
78 
79 namespace
80 {
81     enum
82     {
83         PROP_NONNEGATIVE,
84         PROP_INTEGER,
85         PROP_TIMEOUT,
86         PROP_EPSILONLEVEL,
87         PROP_LIMITBBDEPTH
88     };
89 }
90 
91 // -----------------------------------------------------------------------
92 
93 // hash map for the coefficients of a dependent cell (objective or constraint)
94 // The size of each vector is the number of columns (variable cells) plus one, first entry is initial value.
95 
96 struct ScSolverCellHash
97 {
98     size_t operator()( const table::CellAddress& rAddress ) const
99     {
100         return ( rAddress.Sheet << 24 ) | ( rAddress.Column << 16 ) | rAddress.Row;
101     }
102 };
103 
104 inline bool AddressEqual( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 )
105 {
106     return rAddr1.Sheet == rAddr2.Sheet && rAddr1.Column == rAddr2.Column && rAddr1.Row == rAddr2.Row;
107 }
108 
109 struct ScSolverCellEqual
110 {
111     bool operator()( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 ) const
112     {
113         return AddressEqual( rAddr1, rAddr2 );
114     }
115 };
116 
117 typedef std::hash_map< table::CellAddress, std::vector<double>, ScSolverCellHash, ScSolverCellEqual > ScSolverCellHashMap;
118 
119 // -----------------------------------------------------------------------
120 
121 uno::Reference<table::XCell> lcl_GetCell( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
122                                           const table::CellAddress& rPos )
123 {
124     uno::Reference<container::XIndexAccess> xSheets( xDoc->getSheets(), uno::UNO_QUERY );
125     uno::Reference<sheet::XSpreadsheet> xSheet( xSheets->getByIndex( rPos.Sheet ), uno::UNO_QUERY );
126     return xSheet->getCellByPosition( rPos.Column, rPos.Row );
127 }
128 
129 void lcl_SetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
130                    const table::CellAddress& rPos, double fValue )
131 {
132     lcl_GetCell( xDoc, rPos )->setValue( fValue );
133 }
134 
135 double lcl_GetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
136                      const table::CellAddress& rPos )
137 {
138     return lcl_GetCell( xDoc, rPos )->getValue();
139 }
140 
141 // -------------------------------------------------------------------------
142 
143 SolverComponent::SolverComponent( const uno::Reference<uno::XComponentContext>& /* rSMgr */ ) :
144     OPropertyContainer( GetBroadcastHelper() ),
145     mbMaximize( sal_True ),
146     mbNonNegative( sal_False ),
147     mbInteger( sal_False ),
148     mnTimeout( 100 ),
149     mnEpsilonLevel( 0 ),
150     mbLimitBBDepth( sal_True ),
151     mbSuccess( sal_False ),
152     mfResultValue( 0.0 )
153 {
154     // for XPropertySet implementation:
155     registerProperty( C2U(STR_NONNEGATIVE),  PROP_NONNEGATIVE,  0, &mbNonNegative,  getCppuType( &mbNonNegative )  );
156     registerProperty( C2U(STR_INTEGER),      PROP_INTEGER,      0, &mbInteger,      getCppuType( &mbInteger )      );
157     registerProperty( C2U(STR_TIMEOUT),      PROP_TIMEOUT,      0, &mnTimeout,      getCppuType( &mnTimeout )      );
158     registerProperty( C2U(STR_EPSILONLEVEL), PROP_EPSILONLEVEL, 0, &mnEpsilonLevel, getCppuType( &mnEpsilonLevel ) );
159     registerProperty( C2U(STR_LIMITBBDEPTH), PROP_LIMITBBDEPTH, 0, &mbLimitBBDepth, getCppuType( &mbLimitBBDepth ) );
160 }
161 
162 SolverComponent::~SolverComponent()
163 {
164 }
165 
166 IMPLEMENT_FORWARD_XINTERFACE2( SolverComponent, SolverComponent_Base, OPropertyContainer )
167 IMPLEMENT_FORWARD_XTYPEPROVIDER2( SolverComponent, SolverComponent_Base, OPropertyContainer )
168 
169 cppu::IPropertyArrayHelper* SolverComponent::createArrayHelper() const
170 {
171     uno::Sequence<beans::Property> aProps;
172     describeProperties( aProps );
173     return new cppu::OPropertyArrayHelper( aProps );
174 }
175 
176 cppu::IPropertyArrayHelper& SAL_CALL SolverComponent::getInfoHelper()
177 {
178     return *getArrayHelper();
179 }
180 
181 uno::Reference<beans::XPropertySetInfo> SAL_CALL SolverComponent::getPropertySetInfo() throw(uno::RuntimeException)
182 {
183     return createPropertySetInfo( getInfoHelper() );
184 }
185 
186 // XSolverDescription
187 
188 OUString SAL_CALL SolverComponent::getComponentDescription() throw (uno::RuntimeException)
189 {
190     return lcl_GetResourceString( RID_SOLVER_COMPONENT );
191 }
192 
193 OUString SAL_CALL SolverComponent::getStatusDescription() throw (uno::RuntimeException)
194 {
195     return maStatus;
196 }
197 
198 OUString SAL_CALL SolverComponent::getPropertyDescription( const OUString& rPropertyName ) throw (uno::RuntimeException)
199 {
200     sal_uInt32 nResId = 0;
201 	sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName );
202     switch (nHandle)
203     {
204         case PROP_NONNEGATIVE:
205             nResId = RID_PROPERTY_NONNEGATIVE;
206             break;
207         case PROP_INTEGER:
208             nResId = RID_PROPERTY_INTEGER;
209             break;
210         case PROP_TIMEOUT:
211             nResId = RID_PROPERTY_TIMEOUT;
212             break;
213         case PROP_EPSILONLEVEL:
214             nResId = RID_PROPERTY_EPSILONLEVEL;
215             break;
216         case PROP_LIMITBBDEPTH:
217             nResId = RID_PROPERTY_LIMITBBDEPTH;
218             break;
219         default:
220             {
221                 // unknown - leave empty
222             }
223     }
224     OUString aRet;
225     if ( nResId )
226         aRet = lcl_GetResourceString( nResId );
227     return aRet;
228 }
229 
230 // XSolver: settings
231 
232 uno::Reference<sheet::XSpreadsheetDocument> SAL_CALL SolverComponent::getDocument() throw(uno::RuntimeException)
233 {
234     return mxDoc;
235 }
236 
237 void SAL_CALL SolverComponent::setDocument( const uno::Reference<sheet::XSpreadsheetDocument>& _document )
238                                 throw(uno::RuntimeException)
239 {
240     mxDoc = _document;
241 }
242 
243 table::CellAddress SAL_CALL SolverComponent::getObjective() throw(uno::RuntimeException)
244 {
245     return maObjective;
246 }
247 
248 void SAL_CALL SolverComponent::setObjective( const table::CellAddress& _objective ) throw(uno::RuntimeException)
249 {
250     maObjective = _objective;
251 }
252 
253 uno::Sequence<table::CellAddress> SAL_CALL SolverComponent::getVariables() throw(uno::RuntimeException)
254 {
255     return maVariables;
256 }
257 
258 void SAL_CALL SolverComponent::setVariables( const uno::Sequence<table::CellAddress>& _variables )
259                                 throw(uno::RuntimeException)
260 {
261     maVariables = _variables;
262 }
263 
264 uno::Sequence<sheet::SolverConstraint> SAL_CALL SolverComponent::getConstraints() throw(uno::RuntimeException)
265 {
266     return maConstraints;
267 }
268 
269 void SAL_CALL SolverComponent::setConstraints( const uno::Sequence<sheet::SolverConstraint>& _constraints )
270                                 throw(uno::RuntimeException)
271 {
272     maConstraints = _constraints;
273 }
274 
275 sal_Bool SAL_CALL SolverComponent::getMaximize() throw(uno::RuntimeException)
276 {
277     return mbMaximize;
278 }
279 
280 void SAL_CALL SolverComponent::setMaximize( sal_Bool _maximize ) throw(uno::RuntimeException)
281 {
282     mbMaximize = _maximize;
283 }
284 
285 // XSolver: get results
286 
287 sal_Bool SAL_CALL SolverComponent::getSuccess() throw(uno::RuntimeException)
288 {
289     return mbSuccess;
290 }
291 
292 double SAL_CALL SolverComponent::getResultValue() throw(uno::RuntimeException)
293 {
294     return mfResultValue;
295 }
296 
297 uno::Sequence<double> SAL_CALL SolverComponent::getSolution() throw(uno::RuntimeException)
298 {
299     return maSolution;
300 }
301 
302 // -------------------------------------------------------------------------
303 
304 void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
305 {
306     uno::Reference<frame::XModel> xModel( mxDoc, uno::UNO_QUERY );
307     if ( !xModel.is() )
308         throw uno::RuntimeException();
309 
310     maStatus = OUString();
311     mbSuccess = false;
312 
313     if ( mnEpsilonLevel < EPS_TIGHT || mnEpsilonLevel > EPS_BAGGY )
314     {
315         maStatus = lcl_GetResourceString( RID_ERROR_EPSILONLEVEL );
316         return;
317     }
318 
319     xModel->lockControllers();
320 
321     // collect variables in vector (?)
322 
323     std::vector<table::CellAddress> aVariableCells;
324     for (sal_Int32 nPos=0; nPos<maVariables.getLength(); nPos++)
325         aVariableCells.push_back( maVariables[nPos] );
326     size_t nVariables = aVariableCells.size();
327     size_t nVar = 0;
328 
329     // collect all dependent cells
330 
331     ScSolverCellHashMap aCellsHash;
332     aCellsHash[maObjective].reserve( nVariables + 1 );                  // objective function
333 
334     for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
335     {
336         table::CellAddress aCellAddr = maConstraints[nConstrPos].Left;
337         aCellsHash[aCellAddr].reserve( nVariables + 1 );                // constraints: left hand side
338 
339         if ( maConstraints[nConstrPos].Right >>= aCellAddr )
340             aCellsHash[aCellAddr].reserve( nVariables + 1 );            // constraints: right hand side
341     }
342 
343     // set all variables to zero
344     //! store old values?
345     //! use old values as initial values?
346     std::vector<table::CellAddress>::const_iterator aVarIter;
347     for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter )
348     {
349         lcl_SetValue( mxDoc, *aVarIter, 0.0 );
350     }
351 
352     // read initial values from all dependent cells
353     ScSolverCellHashMap::iterator aCellsIter;
354     for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
355     {
356         double fValue = lcl_GetValue( mxDoc, aCellsIter->first );
357         aCellsIter->second.push_back( fValue );                         // store as first element, as-is
358     }
359 
360     // loop through variables
361     for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter )
362     {
363         lcl_SetValue( mxDoc, *aVarIter, 1.0 );      // set to 1 to examine influence
364 
365         // read value change from all dependent cells
366         for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
367         {
368             double fChanged = lcl_GetValue( mxDoc, aCellsIter->first );
369             double fInitial = aCellsIter->second.front();
370             aCellsIter->second.push_back( fChanged - fInitial );
371         }
372 
373         lcl_SetValue( mxDoc, *aVarIter, 2.0 );      // minimal test for linearity
374 
375         for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
376         {
377             double fInitial = aCellsIter->second.front();
378             double fCoeff   = aCellsIter->second.back();       // last appended: coefficient for this variable
379             double fTwo     = lcl_GetValue( mxDoc, aCellsIter->first );
380 
381             bool bLinear = rtl::math::approxEqual( fTwo, fInitial + 2.0 * fCoeff ) ||
382                            rtl::math::approxEqual( fInitial, fTwo - 2.0 * fCoeff );
383             // second comparison is needed in case fTwo is zero
384             if ( !bLinear )
385                 maStatus = lcl_GetResourceString( RID_ERROR_NONLINEAR );
386         }
387 
388         lcl_SetValue( mxDoc, *aVarIter, 0.0 );      // set back to zero for examining next variable
389     }
390 
391     xModel->unlockControllers();
392 
393     if ( maStatus.getLength() )
394         return;
395 
396     //
397     // build lp_solve model
398     //
399 
400     lprec* lp = make_lp( 0, nVariables );
401     if ( !lp )
402         return;
403 
404     set_outputfile( lp, const_cast<char*>( "" ) );  // no output
405 
406     // set objective function
407 
408     const std::vector<double>& rObjCoeff = aCellsHash[maObjective];
409     REAL* pObjVal = new REAL[nVariables+1];
410     pObjVal[0] = 0.0;                           // ignored
411     for (nVar=0; nVar<nVariables; nVar++)
412         pObjVal[nVar+1] = rObjCoeff[nVar+1];
413     set_obj_fn( lp, pObjVal );
414     delete[] pObjVal;
415     set_rh( lp, 0, rObjCoeff[0] );              // constant term of objective
416 
417     // add rows
418 
419     set_add_rowmode(lp, TRUE);
420 
421     for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
422     {
423         // integer constraints are set later
424         sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator;
425         if ( eOp == sheet::SolverConstraintOperator_LESS_EQUAL ||
426              eOp == sheet::SolverConstraintOperator_GREATER_EQUAL ||
427              eOp == sheet::SolverConstraintOperator_EQUAL )
428         {
429             double fDirectValue = 0.0;
430             bool bRightCell = false;
431             table::CellAddress aRightAddr;
432             const uno::Any& rRightAny = maConstraints[nConstrPos].Right;
433             if ( rRightAny >>= aRightAddr )
434                 bRightCell = true;                  // cell specified as right-hand side
435             else
436                 rRightAny >>= fDirectValue;         // constant value
437 
438             table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
439 
440             const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr];
441             REAL* pValues = new REAL[nVariables+1];
442             pValues[0] = 0.0;                               // ignored?
443             for (nVar=0; nVar<nVariables; nVar++)
444                 pValues[nVar+1] = rLeftCoeff[nVar+1];
445 
446             // if left hand cell has a constant term, put into rhs value
447             double fRightValue = -rLeftCoeff[0];
448 
449             if ( bRightCell )
450             {
451                 const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr];
452                 // modify pValues with rhs coefficients
453                 for (nVar=0; nVar<nVariables; nVar++)
454                     pValues[nVar+1] -= rRightCoeff[nVar+1];
455 
456                 fRightValue += rRightCoeff[0];      // constant term
457             }
458             else
459                 fRightValue += fDirectValue;
460 
461             int nConstrType = LE;
462             switch ( eOp )
463             {
464                 case sheet::SolverConstraintOperator_LESS_EQUAL:    nConstrType = LE; break;
465                 case sheet::SolverConstraintOperator_GREATER_EQUAL: nConstrType = GE; break;
466                 case sheet::SolverConstraintOperator_EQUAL:         nConstrType = EQ; break;
467                 default:
468                     OSL_ENSURE( false, "unexpected enum type" );
469             }
470             add_constraint( lp, pValues, nConstrType, fRightValue );
471 
472             delete[] pValues;
473         }
474     }
475 
476     set_add_rowmode(lp, FALSE);
477 
478     // apply settings to all variables
479 
480     for (nVar=0; nVar<nVariables; nVar++)
481     {
482         if ( !mbNonNegative )
483             set_unbounded(lp, nVar+1);          // allow negative (default is non-negative)
484                                                 //! collect bounds from constraints?
485         if ( mbInteger )
486             set_int(lp, nVar+1, TRUE);
487     }
488 
489     // apply single-var integer constraints
490 
491     for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
492     {
493         sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator;
494         if ( eOp == sheet::SolverConstraintOperator_INTEGER ||
495              eOp == sheet::SolverConstraintOperator_BINARY )
496         {
497             table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
498             // find variable index for cell
499             for (nVar=0; nVar<nVariables; nVar++)
500                 if ( AddressEqual( aVariableCells[nVar], aLeftAddr ) )
501                 {
502                     if ( eOp == sheet::SolverConstraintOperator_INTEGER )
503                         set_int(lp, nVar+1, TRUE);
504                     else
505                         set_binary(lp, nVar+1, TRUE);
506                 }
507         }
508     }
509 
510     if ( mbMaximize )
511         set_maxim(lp);
512     else
513         set_minim(lp);
514 
515     if ( !mbLimitBBDepth )
516         set_bb_depthlimit( lp, 0 );
517 
518     set_epslevel( lp, mnEpsilonLevel );
519     set_timeout( lp, mnTimeout );
520 
521     // solve model
522 
523     int nResult = ::solve( lp );
524 
525     mbSuccess = ( nResult == OPTIMAL );
526     if ( mbSuccess )
527     {
528         // get solution
529 
530         maSolution.realloc( nVariables );
531 
532         REAL* pResultVar = NULL;
533         get_ptr_variables( lp, &pResultVar );
534         for (nVar=0; nVar<nVariables; nVar++)
535             maSolution[nVar] = pResultVar[nVar];
536 
537         mfResultValue = get_objective( lp );
538     }
539     else if ( nResult == INFEASIBLE )
540         maStatus = lcl_GetResourceString( RID_ERROR_INFEASIBLE );
541     else if ( nResult == UNBOUNDED )
542         maStatus = lcl_GetResourceString( RID_ERROR_UNBOUNDED );
543     else if ( nResult == TIMEOUT || nResult == SUBOPTIMAL )
544         maStatus = lcl_GetResourceString( RID_ERROR_TIMEOUT );
545     // SUBOPTIMAL is assumed to be caused by a timeout, and reported as an error
546 
547     delete_lp( lp );
548 }
549 
550 // -------------------------------------------------------------------------
551 
552 // XServiceInfo
553 
554 uno::Sequence< OUString > SolverComponent_getSupportedServiceNames()
555 {
556     uno::Sequence< OUString > aServiceNames( 1 );
557     aServiceNames[ 0 ] = OUString::createFromAscii( "com.sun.star.sheet.Solver" );
558     return aServiceNames;
559 }
560 
561 OUString SolverComponent_getImplementationName()
562 {
563     return OUString::createFromAscii( "com.sun.star.comp.Calc.Solver" );
564 }
565 
566 OUString SAL_CALL SolverComponent::getImplementationName() throw(uno::RuntimeException)
567 {
568     return SolverComponent_getImplementationName();
569 }
570 
571 sal_Bool SAL_CALL SolverComponent::supportsService( const OUString& rServiceName ) throw(uno::RuntimeException)
572 {
573     const uno::Sequence< OUString > aServices = SolverComponent_getSupportedServiceNames();
574     const OUString* pArray = aServices.getConstArray();
575     const OUString* pArrayEnd = pArray + aServices.getLength();
576     return ::std::find( pArray, pArrayEnd, rServiceName ) != pArrayEnd;
577 }
578 
579 uno::Sequence<OUString> SAL_CALL SolverComponent::getSupportedServiceNames() throw(uno::RuntimeException)
580 {
581     return SolverComponent_getSupportedServiceNames();
582 }
583 
584 uno::Reference<uno::XInterface> SolverComponent_createInstance( const uno::Reference<uno::XComponentContext>& rSMgr )
585     throw(uno::Exception)
586 {
587 	return (cppu::OWeakObject*) new SolverComponent( rSMgr );
588 }
589 
590 // -------------------------------------------------------------------------
591 
592 extern "C"
593 {
594     SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment(
595         const sal_Char ** ppEnvTypeName, uno_Environment ** )
596     {
597         *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
598     }
599 
600     // -------------------------------------------------------------------------
601 
602     SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
603     {
604         OUString    aImplName( OUString::createFromAscii( pImplName ) );
605         void*       pRet = 0;
606 
607         if( pServiceManager )
608         {
609             uno::Reference< lang::XSingleComponentFactory > xFactory;
610             if( aImplName.equals( SolverComponent_getImplementationName() ) )
611                 xFactory = cppu::createSingleComponentFactory(
612                         SolverComponent_createInstance,
613                         OUString::createFromAscii( pImplName ),
614                         SolverComponent_getSupportedServiceNames() );
615 
616             if( xFactory.is() )
617             {
618                 xFactory->acquire();
619                 pRet = xFactory.get();
620             }
621         }
622         return pRet;
623     }
624 }
625 
626