ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
saigGlaPba.c File Reference
#include "saig.h"
#include "sat/bsat/satSolver.h"
#include "sat/bsat/satStore.h"
Include dependency graph for saigGlaPba.c:

Go to the source code of this file.

Classes

struct  Aig_Gla2Man_t_
 

Typedefs

typedef typedefABC_NAMESPACE_IMPL_START struct Aig_Gla2Man_t_ Aig_Gla2Man_t
 DECLARATIONS ///.
 

Functions

int Aig_Gla2FetchVar (Aig_Gla2Man_t *p, Aig_Obj_t *pObj, int k)
 
void Aig_Gla2AssignVars_rec (Aig_Gla2Man_t *p, Aig_Obj_t *pObj, int f)
 
int Aig_Gla2CreateSatSolver (Aig_Gla2Man_t *p)
 
Aig_Gla2Man_tAig_Gla2ManStart (Aig_Man_t *pAig, int nStart, int nFramesMax, int fVerbose)
 
void Aig_Gla2ManStop (Aig_Gla2Man_t *p)
 
Vec_Int_tSaig_AbsSolverUnsatCore (sat_solver *pSat, int nConfMax, int fVerbose, int *piRetValue)
 
Vec_Int_tAig_Gla2ManCollect (Aig_Gla2Man_t *p, Vec_Int_t *vCore)
 
Vec_Int_tAig_Gla2ManPerform (Aig_Man_t *pAig, int nStart, int nFramesMax, int nConfLimit, int TimeLimit, int fSkipRand, int fVerbose)
 

Typedef Documentation

◆ Aig_Gla2Man_t

typedef typedefABC_NAMESPACE_IMPL_START struct Aig_Gla2Man_t_ Aig_Gla2Man_t

DECLARATIONS ///.

CFile****************************************************************

FileName [saigGlaPba.c]

SystemName [ABC: Logic synthesis and verification system.]

PackageName [Sequential AIG package.]

Synopsis [Gate level abstraction.]

Author [Alan Mishchenko]

Affiliation [UC Berkeley]

Date [Ver. 1.0. Started - June 20, 2005.]

Revision [

Id
saigGlaPba.c,v 1.00 2005/06/20 00:00:00 alanmi Exp

]

Definition at line 32 of file saigGlaPba.c.

Function Documentation

◆ Aig_Gla2AssignVars_rec()

void Aig_Gla2AssignVars_rec ( Aig_Gla2Man_t * p,
Aig_Obj_t * pObj,
int f )

Function*************************************************************

Synopsis [Assigns variables to the AIG nodes.]

Description []

SideEffects []

SeeAlso []

Definition at line 188 of file saigGlaPba.c.

189{
190 int nVars = Vec_IntSize(p->vVar2Inf);
191 Aig_Gla2FetchVar( p, pObj, f );
192 if ( nVars == Vec_IntSize(p->vVar2Inf) )
193 return;
194 if ( Aig_ObjIsConst1(pObj) )
195 return;
196 if ( Saig_ObjIsPo( p->pAig, pObj ) )
197 {
198 Aig_Gla2AssignVars_rec( p, Aig_ObjFanin0(pObj), f );
199 return;
200 }
201 if ( Aig_ObjIsCi( pObj ) )
202 {
203 if ( Saig_ObjIsLo(p->pAig, pObj) && f > 0 )
204 Aig_Gla2AssignVars_rec( p, Aig_ObjFanin0( Saig_ObjLoToLi(p->pAig, pObj) ), f-1 );
205 return;
206 }
207 assert( Aig_ObjIsNode(pObj) );
208 Aig_Gla2AssignVars_rec( p, Aig_ObjFanin0(pObj), f );
209 Aig_Gla2AssignVars_rec( p, Aig_ObjFanin1(pObj), f );
210}
Cube * p
Definition exorList.c:222
int Aig_Gla2FetchVar(Aig_Gla2Man_t *p, Aig_Obj_t *pObj, int k)
Definition saigGlaPba.c:154
void Aig_Gla2AssignVars_rec(Aig_Gla2Man_t *p, Aig_Obj_t *pObj, int f)
Definition saigGlaPba.c:188
#define assert(ex)
Definition util_old.h:213
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Aig_Gla2CreateSatSolver()

int Aig_Gla2CreateSatSolver ( Aig_Gla2Man_t * p)

Function*************************************************************

Synopsis [Creates SAT solver.]

Description []

SideEffects []

SeeAlso []

Definition at line 223 of file saigGlaPba.c.

224{
225 Vec_Int_t * vPoLits;
226 Aig_Obj_t * pObj;
227 int i, f, ObjId, nVars, RetValue = 1;
228
229 // assign variables
230 for ( f = p->nFramesMax - 1; f >= 0; f-- )
231// for ( f = 0; f < p->nFramesMax; f++ )
232 Aig_Gla2AssignVars_rec( p, Aig_ManCo(p->pAig, 0), f );
233
234 // create SAT solver
235 p->pSat = sat_solver_new();
236 sat_solver_store_alloc( p->pSat );
237 sat_solver_setnvars( p->pSat, Vec_IntSize(p->vVar2Inf)/2 );
238
239 // add clauses
240 nVars = Vec_IntSize( p->vVar2Inf );
241 Vec_IntForEachEntryDouble( p->vVar2Inf, ObjId, f, i )
242 {
243 if ( ObjId == -1 )
244 continue;
245 pObj = Aig_ManObj( p->pAig, ObjId );
246 if ( Aig_ObjIsNode(pObj) )
247 {
248 RetValue &= Aig_Gla2AddNode( p->pSat, Aig_Gla2FetchVar(p, pObj, f),
249 Aig_Gla2FetchVar(p, Aig_ObjFanin0(pObj), f),
250 Aig_Gla2FetchVar(p, Aig_ObjFanin1(pObj), f),
251 Aig_ObjFaninC0(pObj), Aig_ObjFaninC1(pObj) );
252 Vec_IntPush( p->vCla2Obj, ObjId );
253 Vec_IntPush( p->vCla2Obj, ObjId );
254 Vec_IntPush( p->vCla2Obj, ObjId );
255
256 Vec_IntPush( p->vCla2Fra, f );
257 Vec_IntPush( p->vCla2Fra, f );
258 Vec_IntPush( p->vCla2Fra, f );
259 }
260 else if ( Saig_ObjIsLo(p->pAig, pObj) )
261 {
262 if ( f == 0 )
263 {
264 RetValue &= Aig_Gla2AddConst( p->pSat, Aig_Gla2FetchVar(p, pObj, f), 1 );
265 Vec_IntPush( p->vCla2Obj, ObjId );
266
267 Vec_IntPush( p->vCla2Fra, f );
268 }
269 else
270 {
271 Aig_Obj_t * pObjLi = Saig_ObjLoToLi(p->pAig, pObj);
272 RetValue &= Aig_Gla2AddBuffer( p->pSat, Aig_Gla2FetchVar(p, pObj, f),
273 Aig_Gla2FetchVar(p, Aig_ObjFanin0(pObjLi), f-1),
274 Aig_ObjFaninC0(pObjLi) );
275 Vec_IntPush( p->vCla2Obj, ObjId );
276 Vec_IntPush( p->vCla2Obj, ObjId );
277
278 Vec_IntPush( p->vCla2Fra, f );
279 Vec_IntPush( p->vCla2Fra, f );
280 }
281 }
282 else if ( Saig_ObjIsPo(p->pAig, pObj) )
283 {
284 RetValue &= Aig_Gla2AddBuffer( p->pSat, Aig_Gla2FetchVar(p, pObj, f),
285 Aig_Gla2FetchVar(p, Aig_ObjFanin0(pObj), f),
286 Aig_ObjFaninC0(pObj) );
287 Vec_IntPush( p->vCla2Obj, ObjId );
288 Vec_IntPush( p->vCla2Obj, ObjId );
289
290 Vec_IntPush( p->vCla2Fra, f );
291 Vec_IntPush( p->vCla2Fra, f );
292 }
293 else if ( Aig_ObjIsConst1(pObj) )
294 {
295 RetValue &= Aig_Gla2AddConst( p->pSat, Aig_Gla2FetchVar(p, pObj, f), 0 );
296 Vec_IntPush( p->vCla2Obj, ObjId );
297
298 Vec_IntPush( p->vCla2Fra, f );
299 }
300 else assert( Saig_ObjIsPi(p->pAig, pObj) );
301 }
302
303 // add output clause
304 vPoLits = Vec_IntAlloc( p->nFramesMax );
305 for ( f = p->nStart; f < p->nFramesMax; f++ )
306 Vec_IntPush( vPoLits, 2 * Aig_Gla2FetchVar(p, Aig_ManCo(p->pAig, 0), f) );
307 RetValue &= sat_solver_addclause( p->pSat, Vec_IntArray(vPoLits), Vec_IntArray(vPoLits) + Vec_IntSize(vPoLits) );
308 Vec_IntFree( vPoLits );
309 Vec_IntPush( p->vCla2Obj, 0 );
310 Vec_IntPush( p->vCla2Fra, 0 );
311 assert( Vec_IntSize(p->vCla2Fra) == Vec_IntSize(p->vCla2Obj) );
312
313 assert( nVars == Vec_IntSize(p->vVar2Inf) );
314 assert( ((Sto_Man_t *)p->pSat->pStore)->nClauses == Vec_IntSize(p->vCla2Obj) );
315// Sto_ManDumpClauses( ((Sto_Man_t *)p->pSat->pStore), "temp_sto.cnf" );
317
318 if ( p->fVerbose )
319 printf( "The resulting SAT problem contains %d variables and %d clauses.\n",
320 p->pSat->size, p->pSat->stats.clauses );
321 return RetValue;
322}
struct Aig_Obj_t_ Aig_Obj_t
Definition aig.h:51
typedefABC_NAMESPACE_IMPL_START struct Vec_Int_t_ Vec_Int_t
DECLARATIONS ///.
Definition bblif.c:37
#define sat_solver_addclause
Definition cecSatG2.c:37
sat_solver * sat_solver_new(void)
Definition satSolver.c:1137
void sat_solver_setnvars(sat_solver *s, int n)
Definition satSolver.c:1272
void sat_solver_store_alloc(sat_solver *s)
Definition satSolver.c:2389
void sat_solver_store_mark_roots(sat_solver *s)
Definition satSolver.c:2412
struct Sto_Man_t_ Sto_Man_t
Definition satStore.h:81
#define Vec_IntForEachEntryDouble(vVec, Entry1, Entry2, i)
Definition vecInt.h:72
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Aig_Gla2FetchVar()

int Aig_Gla2FetchVar ( Aig_Gla2Man_t * p,
Aig_Obj_t * pObj,
int k )

Function*************************************************************

Synopsis [Finds existing SAT variable or creates a new one.]

Description []

SideEffects []

SeeAlso []

Definition at line 154 of file saigGlaPba.c.

155{
156 int i, iVecId, iSatVar;
157 assert( k < p->nFramesMax );
158 iVecId = Vec_IntEntry( p->vObj2Vec, Aig_ObjId(pObj) );
159 if ( iVecId == 0 )
160 {
161 iVecId = Vec_IntSize( p->vVec2Var ) / p->nFramesMax;
162 for ( i = 0; i < p->nFramesMax; i++ )
163 Vec_IntPush( p->vVec2Var, 0 );
164 Vec_IntWriteEntry( p->vObj2Vec, Aig_ObjId(pObj), iVecId );
165 }
166 iSatVar = Vec_IntEntry( p->vVec2Var, iVecId * p->nFramesMax + k );
167 if ( iSatVar == 0 )
168 {
169 iSatVar = Vec_IntSize( p->vVar2Inf ) / 2;
170 Vec_IntPush( p->vVar2Inf, Aig_ObjId(pObj) );
171 Vec_IntPush( p->vVar2Inf, k );
172 Vec_IntWriteEntry( p->vVec2Var, iVecId * p->nFramesMax + k, iSatVar );
173 }
174 return iSatVar;
175}
Here is the caller graph for this function:

◆ Aig_Gla2ManCollect()

Vec_Int_t * Aig_Gla2ManCollect ( Aig_Gla2Man_t * p,
Vec_Int_t * vCore )

Function*************************************************************

Synopsis [Collects abstracted objects.]

Description []

SideEffects []

SeeAlso []

Definition at line 454 of file saigGlaPba.c.

455{
456 Vec_Int_t * vResult;
457 Aig_Obj_t * pObj;
458 int i, ClaId, iVecId;
459// p->vVec2Use = Vec_IntStart( Vec_IntSize(p->vVec2Var) );
460
461 vResult = Vec_IntStart( Aig_ManObjNumMax(p->pAig) );
462 Vec_IntWriteEntry( vResult, 0, 1 ); // add const1
463 Vec_IntForEachEntry( vCore, ClaId, i )
464 {
465 pObj = Aig_ManObj( p->pAig, Vec_IntEntry(p->vCla2Obj, ClaId) );
466 if ( Saig_ObjIsPi(p->pAig, pObj) || Saig_ObjIsPo(p->pAig, pObj) || Aig_ObjIsConst1(pObj) )
467 continue;
468 assert( Saig_ObjIsLo(p->pAig, pObj) || Aig_ObjIsNode(pObj) );
469 Vec_IntWriteEntry( vResult, Aig_ObjId(pObj), 1 );
470/*
471 // add flop inputs with multiple fanouts
472 if ( Saig_ObjIsLo(p->pAig, pObj) )
473 {
474 Aig_Obj_t * pObjLi = Saig_ObjLoToLi(p->pAig, pObj);
475 if ( !Saig_ObjIsPi(p->pAig, Aig_ObjFanin0(pObjLi)) )
476// if ( Aig_ObjRefs( Aig_ObjFanin0(pObjLi) ) > 1 )
477 Vec_IntWriteEntry( vResult, Aig_ObjFaninId0(pObjLi), 1 );
478 }
479 else
480 {
481 if ( !Saig_ObjIsPi(p->pAig, Aig_ObjFanin0(pObj)) )
482 Vec_IntWriteEntry( vResult, Aig_ObjFaninId0(pObj), 1 );
483 if ( !Saig_ObjIsPi(p->pAig, Aig_ObjFanin1(pObj)) )
484 Vec_IntWriteEntry( vResult, Aig_ObjFaninId1(pObj), 1 );
485 }
486*/
487 if ( p->vVec2Use )
488 {
489 iVecId = Vec_IntEntry( p->vObj2Vec, Aig_ObjId(pObj) );
490 Vec_IntWriteEntry( p->vVec2Use, iVecId * p->nFramesMax + Vec_IntEntry(p->vCla2Fra, ClaId), 1 );
491 }
492 }
493// printf( "Number of entries %d\n", Vec_IntCountPositive(vResult) );
494
495 // count the number of objects in each frame
496 if ( p->vVec2Use )
497 {
498 Vec_Int_t * vCounts = Vec_IntStart( p->nFramesMax );
499 int v, f, Entry, nVecIds = Vec_IntSize(p->vVec2Use) / p->nFramesMax;
500 for ( f = 0; f < p->nFramesMax; f++ )
501 for ( v = 0; v < nVecIds; v++ )
502 if ( Vec_IntEntry( p->vVec2Use, v * p->nFramesMax + f ) )
503 Vec_IntAddToEntry( vCounts, f, 1 );
504 Vec_IntForEachEntry( vCounts, Entry, f )
505 printf( "%d ", Entry );
506 printf( "\n" );
507 Vec_IntFree( vCounts );
508 }
509 return vResult;
510}
#define Vec_IntForEachEntry(vVec, Entry, i)
MACRO DEFINITIONS ///.
Definition vecInt.h:54
Here is the caller graph for this function:

◆ Aig_Gla2ManPerform()

Vec_Int_t * Aig_Gla2ManPerform ( Aig_Man_t * pAig,
int nStart,
int nFramesMax,
int nConfLimit,
int TimeLimit,
int fSkipRand,
int fVerbose )

Function*************************************************************

Synopsis [Performs gate-level localization abstraction.]

Description [Returns array of objects included in the abstraction. This array may contain only const1, flop outputs, and internal nodes, that is, objects that should have clauses added to the SAT solver.]

SideEffects []

SeeAlso []

Definition at line 525 of file saigGlaPba.c.

526{
528 Vec_Int_t * vCore, * vResult;
529 clock_t nTimeToStop = TimeLimit ? TimeLimit * CLOCKS_PER_SEC + clock(): 0;
530 clock_t clk, clk2 = clock();
531 assert( Saig_ManPoNum(pAig) == 1 );
532
533 if ( fVerbose )
534 {
535 if ( TimeLimit )
536 printf( "Abstracting from frame %d to frame %d with timeout %d sec.\n", nStart, nFramesMax, TimeLimit );
537 else
538 printf( "Abstracting from frame %d to frame %d with no timeout.\n", nStart, nFramesMax );
539 }
540
541 // start the solver
542 clk = clock();
543 p = Aig_Gla2ManStart( pAig, nStart, nFramesMax, fVerbose );
544 if ( !Aig_Gla2CreateSatSolver( p ) )
545 {
546 printf( "Error! SAT solver became UNSAT.\n" );
548 return NULL;
549 }
550 sat_solver_set_random( p->pSat, fSkipRand );
551 p->timePre += clock() - clk;
552
553 // set runtime limit
554 if ( TimeLimit )
555 sat_solver_set_runtime_limit( p->pSat, nTimeToStop );
556
557 // compute UNSAT core
558 clk = clock();
559 vCore = Saig_AbsSolverUnsatCore( p->pSat, nConfLimit, fVerbose, NULL );
560 if ( vCore == NULL )
561 {
563 return NULL;
564 }
565 p->timeSat += clock() - clk;
566 p->timeTotal += clock() - clk2;
567
568 // print stats
569 if ( fVerbose )
570 {
571 ABC_PRTP( "Pre ", p->timePre, p->timeTotal );
572 ABC_PRTP( "Sat ", p->timeSat, p->timeTotal );
573 ABC_PRTP( "Total ", p->timeTotal, p->timeTotal );
574 }
575
576 // prepare return value
577 vResult = Aig_Gla2ManCollect( p, vCore );
578 Vec_IntFree( vCore );
580 return vResult;
581}
#define ABC_PRTP(a, t, T)
Definition abc_global.h:258
Aig_Gla2Man_t * Aig_Gla2ManStart(Aig_Man_t *pAig, int nStart, int nFramesMax, int fVerbose)
Definition saigGlaPba.c:335
Vec_Int_t * Saig_AbsSolverUnsatCore(sat_solver *pSat, int nConfMax, int fVerbose, int *piRetValue)
Definition saigGlaPba.c:399
void Aig_Gla2ManStop(Aig_Gla2Man_t *p)
Definition saigGlaPba.c:373
Vec_Int_t * Aig_Gla2ManCollect(Aig_Gla2Man_t *p, Vec_Int_t *vCore)
Definition saigGlaPba.c:454
typedefABC_NAMESPACE_IMPL_START struct Aig_Gla2Man_t_ Aig_Gla2Man_t
DECLARATIONS ///.
Definition saigGlaPba.c:32
int Aig_Gla2CreateSatSolver(Aig_Gla2Man_t *p)
Definition saigGlaPba.c:223
Here is the call graph for this function:

◆ Aig_Gla2ManStart()

Aig_Gla2Man_t * Aig_Gla2ManStart ( Aig_Man_t * pAig,
int nStart,
int nFramesMax,
int fVerbose )

Function*************************************************************

Synopsis []

Description []

SideEffects []

SeeAlso []

Definition at line 335 of file saigGlaPba.c.

336{
338 int i;
339
340 p = ABC_CALLOC( Aig_Gla2Man_t, 1 );
341 p->pAig = pAig;
342
343 p->vObj2Vec = Vec_IntStart( Aig_ManObjNumMax(pAig) );
344 p->vVec2Var = Vec_IntAlloc( 1 << 20 );
345 p->vVar2Inf = Vec_IntAlloc( 1 << 20 );
346 p->vCla2Obj = Vec_IntAlloc( 1 << 20 );
347 p->vCla2Fra = Vec_IntAlloc( 1 << 20 );
348
349 // skip first vector ID
350 p->nStart = nStart;
351 p->nFramesMax = nFramesMax;
352 p->fVerbose = fVerbose;
353 for ( i = 0; i < p->nFramesMax; i++ )
354 Vec_IntPush( p->vVec2Var, -1 );
355
356 // skip first SAT variable
357 Vec_IntPush( p->vVar2Inf, -1 );
358 Vec_IntPush( p->vVar2Inf, -1 );
359 return p;
360}
#define ABC_CALLOC(type, num)
Definition abc_global.h:265
Here is the caller graph for this function:

◆ Aig_Gla2ManStop()

void Aig_Gla2ManStop ( Aig_Gla2Man_t * p)

Function*************************************************************

Synopsis []

Description []

SideEffects []

SeeAlso []

Definition at line 373 of file saigGlaPba.c.

374{
375 Vec_IntFreeP( &p->vObj2Vec );
376 Vec_IntFreeP( &p->vVec2Var );
377 Vec_IntFreeP( &p->vVar2Inf );
378 Vec_IntFreeP( &p->vCla2Obj );
379 Vec_IntFreeP( &p->vCla2Fra );
380 Vec_IntFreeP( &p->vVec2Use );
381
382 if ( p->pSat )
383 sat_solver_delete( p->pSat );
384 ABC_FREE( p );
385}
#define ABC_FREE(obj)
Definition abc_global.h:267
void sat_solver_delete(sat_solver *s)
Definition satSolver.c:1341
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Saig_AbsSolverUnsatCore()

Vec_Int_t * Saig_AbsSolverUnsatCore ( sat_solver * pSat,
int nConfMax,
int fVerbose,
int * piRetValue )

Function*************************************************************

Synopsis [Finds the set of clauses involved in the UNSAT core.]

Description []

SideEffects []

SeeAlso []

Definition at line 399 of file saigGlaPba.c.

400{
401 Vec_Int_t * vCore;
402 void * pSatCnf;
403 Intp_Man_t * pManProof;
404 int RetValue;
405 clock_t clk = clock();
406 if ( piRetValue )
407 *piRetValue = -1;
408 // solve the problem
409 RetValue = sat_solver_solve( pSat, NULL, NULL, (ABC_INT64_T)nConfMax, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 );
410 if ( RetValue == l_Undef )
411 {
412 printf( "Conflict limit is reached.\n" );
413 return NULL;
414 }
415 if ( RetValue == l_True )
416 {
417 printf( "The BMC problem is SAT.\n" );
418 if ( piRetValue )
419 *piRetValue = 0;
420 return NULL;
421 }
422 if ( fVerbose )
423 {
424 printf( "SAT solver returned UNSAT after %7d conflicts. ", (int)pSat->stats.conflicts );
425 Abc_PrintTime( 1, "Time", clock() - clk );
426 }
427 assert( RetValue == l_False );
428 pSatCnf = sat_solver_store_release( pSat );
429 // derive the UNSAT core
430 clk = clock();
431 pManProof = Intp_ManAlloc();
432 vCore = (Vec_Int_t *)Intp_ManUnsatCore( pManProof, (Sto_Man_t *)pSatCnf, 0, 0 );
433 Intp_ManFree( pManProof );
434 if ( fVerbose )
435 {
436 printf( "SAT core contains %8d clauses (out of %8d). ", Vec_IntSize(vCore), sat_solver_nclauses(pSat) );
437 Abc_PrintTime( 1, "Time", clock() - clk );
438 }
439 Sto_ManFree( (Sto_Man_t *)pSatCnf );
440 return vCore;
441}
#define l_True
Definition bmcBmcS.c:35
#define l_Undef
Definition bmcBmcS.c:34
#define l_False
Definition bmcBmcS.c:36
#define sat_solver_solve
Definition cecSatG2.c:45
void * Intp_ManUnsatCore(Intp_Man_t *p, Sto_Man_t *pCnf, int fLearned, int fVerbose)
Definition satInterP.c:963
void Intp_ManFree(Intp_Man_t *p)
Definition satInterP.c:178
Intp_Man_t * Intp_ManAlloc()
FUNCTION DEFINITIONS ///.
Definition satInterP.c:96
int sat_solver_nclauses(sat_solver *s)
Definition satSolver.c:2375
void * sat_solver_store_release(sat_solver *s)
Definition satSolver.c:2422
void Sto_ManFree(Sto_Man_t *p)
Definition satStore.c:143
struct Intp_Man_t_ Intp_Man_t
Definition satStore.h:142
stats_t stats
Definition satSolver.h:163
ABC_INT64_T conflicts
Definition satVec.h:156
Here is the call graph for this function:
Here is the caller graph for this function: