本文整理汇总了C++中IsNode函数的典型用法代码示例。如果您正苦于以下问题:C++ IsNode函数的具体用法?C++ IsNode怎么用?C++ IsNode使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了IsNode函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。
示例1: getHardwareType
Hardware::MinorType getHardwareType(string name, HardwareType ht, const Database *const pDB) throw (Error)
{
xmlKeepBlanksDefault(0);
xmlDocPtr doc;
try
{
doc = xmlParseFile(pDB->getHWPath(name, ht).c_str());
}
catch (...)
{
throw;
}
if (doc == 0) throw Error("Cannot initialize XML parser");
xmlNodePtr cur = xmlDocGetRootElement(doc);
if (cur == 0)
{
xmlFreeDoc(doc);
throw Error("XML document is empty, invalid hardware file");
}
string strIFace("NA");
bool bFound = false;
cur = cur->xmlChildrenNode;
while (cur != 0 && !bFound)
{
if (IsNode(cur, "hardware"))
{
xmlNodePtr save = cur;
cur = cur->xmlChildrenNode;
while (cur != 0)
{
if (IsNode(cur, "interface"))
{
strIFace = GetVal(doc, cur);
bFound = true;
break;
}
cur = cur->next;
}
cur = save;
}
cur = cur->next;
}
xmlFreeDoc(doc);
xmlCleanupParser();
if (strIFace == "ethernet") return Hardware::BBEth;
if (strIFace == "usb") return Hardware::BBUSB;
if (strIFace == "usb||ethernet") return Hardware::BBDual;
return Hardware::Unknown;
}
开发者ID:BackupTheBerlios,项目名称:kinneret,代码行数:60,代码来源:hardware.cpp
示例2: IAssertR
int TNGraph::AddEdge(const int& SrcNId, const int& DstNId) {
IAssertR(IsNode(SrcNId) && IsNode(DstNId), TStr::Fmt("%d or %d not a node.", SrcNId, DstNId).CStr());
//IAssert(! IsEdge(SrcNId, DstNId));
if (IsEdge(SrcNId, DstNId)) { return -2; }
GetNode(SrcNId).OutNIdV.AddSorted(DstNId);
GetNode(DstNId).InNIdV.AddSorted(SrcNId);
return -1; // edge id
}
开发者ID:SherlockYang,项目名称:Archive,代码行数:8,代码来源:graph.cpp
示例3: GetNode
int TNGraph::AddEdge2(const int& SrcNId, const int& DstNId) {
if (! IsNode(SrcNId)) { AddNode(SrcNId); }
if (! IsNode(DstNId)) { AddNode(DstNId); }
if (GetNode(SrcNId).IsOutNId(DstNId)) { return -2; } // edge already exists
GetNode(SrcNId).OutNIdV.AddSorted(DstNId);
GetNode(DstNId).InNIdV.AddSorted(SrcNId);
return -1; // no edge id
}
开发者ID:arbenson,项目名称:snap,代码行数:8,代码来源:graph.cpp
示例4: IAssertR
// Add an edge between SrcNId and DstNId to the graph.
int TUNGraph::AddEdge(const int& SrcNId, const int& DstNId) {
IAssertR(IsNode(SrcNId) && IsNode(DstNId), TStr::Fmt("%d or %d not a node.", SrcNId, DstNId).CStr());
if (IsEdge(SrcNId, DstNId)) { return -2; } // edge already exists
GetNode(SrcNId).NIdV.AddSorted(DstNId);
if (SrcNId!=DstNId) { // not a self edge
GetNode(DstNId).NIdV.AddSorted(SrcNId); }
return -1; // edge id
}
开发者ID:RoyZhengGao,项目名称:CommunityEvaluation,代码行数:9,代码来源:graph.cpp
示例5: IAssertR
void TMultimodalGraphImplB::DelEdge(const TPair<TInt,TInt>& SrcNId, const TPair<TInt,TInt>& DstNId) {
IAssertR(IsNode(SrcNId) && IsNode(DstNId), TStr::Fmt("%d or %d not a node.", SrcNId.GetVal2(), DstNId.GetVal2()).CStr());
if (!IsEdge(SrcNId, DstNId)) {
return; // Edge doesn't exist
}
NEdges--;
TPair<TInt,TInt> ModeIdsKey = GetModeIdsKey(SrcNId.GetVal1(), DstNId.GetVal1());
Graphs.GetDat(ModeIdsKey).DelEdge(SrcNId.GetVal2(), DstNId.GetVal2());
}
开发者ID:deepakn94,项目名称:snap-dev,代码行数:10,代码来源:multimodalGraphImplB.cpp
示例6: MxEId
int TNEGraph::AddEdge(const int& SrcNId, const int& DstNId, int EId) {
if (EId == -1) { EId = MxEId; MxEId++; }
else { MxEId = TMath::Mx(EId+1, MxEId()); }
IAssert(! IsEdge(EId));
IAssertR(IsNode(SrcNId) && IsNode(DstNId), TStr::Fmt("%d or %d not a node.", SrcNId, DstNId).CStr());
EdgeH.AddDat(EId, TEdge(EId, SrcNId, DstNId));
GetNode(SrcNId).OutEIdV.AddSorted(EId);
GetNode(DstNId).InEIdV.AddSorted(EId);
return EId;
}
开发者ID:SherlockYang,项目名称:Archive,代码行数:10,代码来源:graph.cpp
示例7: IsEdge
bool TMultimodalGraphImplB::IsEdge(const TPair<TInt,TInt>& SrcNId, const TPair<TInt,TInt>& DstNId) const {
if (!IsNode(SrcNId) || !IsNode(DstNId)) return false;
TPair<TInt,TInt> ModeIdsKey = GetModeIdsKey(SrcNId.GetVal1(), DstNId.GetVal2());
if (!Graphs.IsKey(ModeIdsKey)) {
return false;
}
return Graphs.GetDat(ModeIdsKey).IsEdge(SrcNId.GetVal2(), DstNId.GetVal2());
}
开发者ID:deepakn94,项目名称:snap-dev,代码行数:10,代码来源:multimodalGraphImplB.cpp
示例8: MxEId
int TNEANetMP::AddEdge(const int& SrcNId, const int& DstNId, int EId) {
int i;
if (EId == -1) {
EId = MxEId;
MxEId++;
}
else {
MxEId = TMath::Mx(EId+1, MxEId());
}
IAssertR(!IsEdge(EId), TStr::Fmt("EdgeId %d already exists", EId));
IAssertR(IsNode(SrcNId) && IsNode(DstNId), TStr::Fmt("%d or %d not a node.", SrcNId, DstNId).CStr());
EdgeH.AddDat(EId, TEdge(EId, SrcNId, DstNId));
GetNode(SrcNId).OutEIdV.AddSorted(EId);
GetNode(DstNId).InEIdV.AddSorted(EId);
// update attribute columns
for (i = 0; i < VecOfIntVecsE.Len(); i++) {
TVec<TInt>& IntVec = VecOfIntVecsE[i];
IntVec.Ins(EdgeH.GetKeyId(EId), TInt::Mn);
}
TVec<TStr> DefIntVec = TVec<TStr>();
IntDefaultsE.GetKeyV(DefIntVec);
for (i = 0; i < DefIntVec.Len(); i++) {
TStr attr = DefIntVec[i];
TVec<TInt>& IntVec = VecOfIntVecsE[KeyToIndexTypeE.GetDat(DefIntVec[i]).Val2];
IntVec[EdgeH.GetKeyId(EId)] = GetIntAttrDefaultE(attr);
}
for (i = 0; i < VecOfStrVecsE.Len(); i++) {
TVec<TStr>& StrVec = VecOfStrVecsE[i];
StrVec.Ins(EdgeH.GetKeyId(EId), TStr::GetNullStr());
}
TVec<TStr> DefStrVec = TVec<TStr>();
IntDefaultsE.GetKeyV(DefStrVec);
for (i = 0; i < DefStrVec.Len(); i++) {
TStr attr = DefStrVec[i];
TVec<TStr>& StrVec = VecOfStrVecsE[KeyToIndexTypeE.GetDat(DefStrVec[i]).Val2];
StrVec[EdgeH.GetKeyId(EId)] = GetStrAttrDefaultE(attr);
}
for (i = 0; i < VecOfFltVecsE.Len(); i++) {
TVec<TFlt>& FltVec = VecOfFltVecsE[i];
FltVec.Ins(EdgeH.GetKeyId(EId), TFlt::Mn);
}
TVec<TStr> DefFltVec = TVec<TStr>();
FltDefaultsE.GetKeyV(DefFltVec);
for (i = 0; i < DefFltVec.Len(); i++) {
TStr attr = DefFltVec[i];
TVec<TFlt>& FltVec = VecOfFltVecsE[KeyToIndexTypeE.GetDat(DefFltVec[i]).Val2];
FltVec[NodeH.GetKeyId(EId)] = GetFltAttrDefaultE(attr);
}
return EId;
}
开发者ID:roks,项目名称:snap-dev1,代码行数:54,代码来源:networkmp.cpp
示例9: TransProb
double TCascade::TransProb(const int& NId1, const int& NId2) const {
if (! IsNode(NId1) || ! IsNode(NId2)) { return Eps; }
if (GetTm(NId1) >= GetTm(NId2)) { return Eps; }
if (Model==0)
return Alpha*exp(-Alpha*(GetTm(NId2)-GetTm(NId1))); // exponential
else if (Model==1)
return (Alpha-1)*pow((GetTm(NId2)-GetTm(NId1)), -Alpha); // power-law
else
return Alpha*(GetTm(NId2)-GetTm(NId1))*exp(-0.5*Alpha*pow(GetTm(NId2)-GetTm(NId1), 2)); // rayleigh
return (-1);
}
开发者ID:hmipakchi,项目名称:FinalYearProject,代码行数:12,代码来源:test_cascade_inference.cpp
示例10: markSmall
/* markSmall:
* cp corresponds to a real node. If it is small, its associated cells should
* be marked as usable.
*/
static void
markSmall (cell* cp, sgraph* g)
{
int i;
snode* onp;
cell* ocp;
if (IS_SMALL(cp->bb.UR.y-cp->bb.LL.y)) {
for (i = 0; i < cp->nsides; i++) {
onp = cp->sides[i];
if (!onp->isVert) continue;
if (onp->cells[0] == cp) { /* onp on the right of cp */
ocp = onp->cells[1];
ocp->flags |= MZ_SMALLV;
while ((onp = ocp->sides[M_RIGHT]) && !IsNode(onp->cells[1])) {
ocp = onp->cells[1];
ocp->flags |= MZ_SMALLV;
}
}
else { /* onp on the left of cp */
ocp = onp->cells[0];
ocp->flags |= MZ_SMALLV;
while ((onp = ocp->sides[M_LEFT]) && !IsNode(onp->cells[0])) {
ocp = onp->cells[0];
ocp->flags |= MZ_SMALLV;
}
}
}
}
if (IS_SMALL(cp->bb.UR.x-cp->bb.LL.x)) {
for (i = 0; i < cp->nsides; i++) {
onp = cp->sides[i];
if (onp->isVert) continue;
if (onp->cells[0] == cp) { /* onp on the top of cp */
ocp = onp->cells[1];
ocp->flags |= MZ_SMALLH;
while ((onp = ocp->sides[M_TOP]) && !IsNode(onp->cells[1])) {
ocp = onp->cells[1];
ocp->flags |= MZ_SMALLH;
}
}
else { /* onp on the bottom of cp */
ocp = onp->cells[0];
ocp->flags |= MZ_SMALLH;
while ((onp = ocp->sides[M_BOTTOM]) && !IsNode(onp->cells[0])) {
ocp = onp->cells[0];
ocp->flags |= MZ_SMALLH;
}
}
}
}
}
开发者ID:AhmedAMohamed,项目名称:graphviz,代码行数:57,代码来源:maze.c
示例11: IsOk
bool TNEGraph::IsOk(const bool& ThrowExcept) const {
bool RetVal = true;
for (int N = NodeH.FFirstKeyId(); NodeH.FNextKeyId(N); ) {
const TNode& Node = NodeH[N];
if (! Node.OutEIdV.IsSorted()) {
const TStr Msg = TStr::Fmt("Out-edge list of node %d is not sorted.", Node.GetId());
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
if (! Node.InEIdV.IsSorted()) {
const TStr Msg = TStr::Fmt("In-edge list of node %d is not sorted.", Node.GetId());
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
// check out-edge ids
int prevEId = -1;
for (int e = 0; e < Node.GetOutDeg(); e++) {
if (! IsEdge(Node.GetOutEId(e))) {
const TStr Msg = TStr::Fmt("Out-edge id %d of node %d does not exist.", Node.GetOutEId(e), Node.GetId());
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
if (e > 0 && prevEId == Node.GetOutEId(e)) {
const TStr Msg = TStr::Fmt("Node %d has duplidate out-edge id %d.", Node.GetId(), Node.GetOutEId(e));
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
prevEId = Node.GetOutEId(e);
}
// check in-edge ids
prevEId = -1;
for (int e = 0; e < Node.GetInDeg(); e++) {
if (! IsEdge(Node.GetInEId(e))) {
const TStr Msg = TStr::Fmt("Out-edge id %d of node %d does not exist.", Node.GetInEId(e), Node.GetId());
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
if (e > 0 && prevEId == Node.GetInEId(e)) {
const TStr Msg = TStr::Fmt("Node %d has duplidate out-edge id %d.", Node.GetId(), Node.GetInEId(e));
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
prevEId = Node.GetInEId(e);
}
}
for (int E = EdgeH.FFirstKeyId(); EdgeH.FNextKeyId(E); ) {
const TEdge& Edge = EdgeH[E];
if (! IsNode(Edge.GetSrcNId())) {
const TStr Msg = TStr::Fmt("Edge %d source node %d does not exist.", Edge.GetId(), Edge.GetSrcNId());
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
if (! IsNode(Edge.GetDstNId())) {
const TStr Msg = TStr::Fmt("Edge %d destination node %d does not exist.", Edge.GetId(), Edge.GetDstNId());
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); } RetVal=false;
}
}
return RetVal;
}
开发者ID:SherlockYang,项目名称:Archive,代码行数:52,代码来源:graph.cpp
示例12: UpdateProb
// update the cascade probability given a new edge (N1, N2) in the graph
double TCascade::UpdateProb(const int& N1, const int& N2, const bool& UpdateProb) {
if (!IsNode(N1) || !IsNode(N2)) { return CurProb; }
if (GetTm(N1) >= GetTm(N2)) { return CurProb; }
const double P1 = log(TransProb(GetParent(N2), N2));
const double P2 = log(TransProb(N1, N2)); // N1 influences N2
if (P1 < P2) {
if (UpdateProb) { // the edge is there, update the CurProb and best Parent
CurProb = CurProb - P1 + P2;
NIdHitH.GetDat(N2).Parent = N1;
} else {
return CurProb - P1 + P2; }
}
return CurProb;
}
开发者ID:hmipakchi,项目名称:FinalYearProject,代码行数:15,代码来源:test_cascade_inference.cpp
示例13: RestoreProps
void RestoreProps(struct xmlNode *input, PROJECTITEM *root, PROJECTITEM *parent)
{
while (input)
{
if (IsNode(input, "PROP"))
{
// oldformat
struct xmlAttr *attribs = input->attribs;
char *id = NULL;
while (attribs)
{
if (IsAttrib(attribs, "ID"))
id = attribs->value;
attribs = attribs->next;
}
if (strcmp(id, "__DEBUG"))
{
PROFILE *p = parent->profiles;
while (p)
{
if (!stricmp(p->name, "WIN32"))
{
break;
}
p = p->next;
}
if (!p)
{
PROFILE **q = &parent->profiles;
while (*q) q= &(*q)->next;
*q = calloc(1, sizeof(PROFILE));
(*q)->name = sysProfileName;
p = *q;
}
if (p)
{
RestoreOneProp(input, &p->debugSettings);
RestoreOneProp(input, &p->releaseSettings);
}
}
}
else if (IsNode(input, "PROFILE"))
{
RestoreProfileProps(input, root, parent);
}
input = input->next;
}
}
开发者ID:doniexun,项目名称:OrangeC,代码行数:48,代码来源:slproj.c
示例14: emitSearchGraph
static void
emitSearchGraph (FILE* fp, sgraph* sg)
{
cell* cp;
snode* np;
sedge* ep;
point p;
int i;
fputs ("graph G {\n", fp);
fputs (" node[shape=point]\n", fp);
for (i = 0; i < sg->nnodes; i++) {
np = sg->nodes+i;
cp = np->cells[0];
if (cp == np->cells[1]) {
pointf pf = midPt (cp);
p.x = pf.x;
p.y = pf.y;
}
else {
if (IsNode(cp)) cp = np->cells[1];
p = coordOf (cp, np);
}
fprintf (fp, " %d [pos=\"%d,%d\"]\n", i, p.x, p.y);
}
for (i = 0; i < sg->nedges; i++) {
ep = sg->edges+i;
fprintf (fp, " %d -- %d[len=\"%f\"]\n", ep->v1, ep->v2, ep->weight);
}
fputs ("}\n", fp);
}
开发者ID:TidyHuang,项目名称:vizgems,代码行数:30,代码来源:ortho.c
示例15: if
int TUNGraph::AddNode(int NId) {
if (NId == -1) { NId = MxNId; MxNId++; }
else if (IsNode(NId)) { return NId; } // already a node
else { MxNId = TMath::Mx(NId+1, MxNId()); }
NodeH.AddDat(NId, TNode(NId));
return NId;
}
开发者ID:SherlockYang,项目名称:Archive,代码行数:7,代码来源:graph.cpp
示例16: RestoreGeneralProps
void RestoreGeneralProps(struct xmlNode *node, int version)
{
node = node->children;
while (node)
{
if (IsNode(node, "PROP"))
{
struct xmlAttr *attribs = node->attribs;
char *id = NULL;
while (attribs)
{
if (IsAttrib(attribs, "ID"))
id = attribs->value;
attribs = attribs->next;
}
if (id)
{
SETTING *setting = PropFind(NULL, id);
if (!setting)
{
setting = calloc(1, sizeof(SETTING));
setting->type = e_text;
setting->id = strdup(id);
InsertSetting(&generalProject, setting);
}
if (setting)
{
free(setting->value);
setting->value = strdup(node->textData);
}
}
}
node = node->next;
}
}
开发者ID:jossk,项目名称:OrangeC,代码行数:35,代码来源:slprefs.c
示例17: IsOk
// Check the graph data structure for internal consistency.
bool TUNGraph::IsOk(const bool& ThrowExcept) const {
bool RetVal = true;
for (int N = NodeH.FFirstKeyId(); NodeH.FNextKeyId(N); ) {
const TNode& Node = NodeH[N];
if (! Node.NIdV.IsSorted()) {
const TStr Msg = TStr::Fmt("Neighbor list of node %d is not sorted.", Node.GetId());
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); }
RetVal=false;
}
int prevNId = -1;
for (int e = 0; e < Node.GetDeg(); e++) {
if (! IsNode(Node.GetNbrNId(e))) {
const TStr Msg = TStr::Fmt("Edge %d --> %d: node %d does not exist.",
Node.GetId(), Node.GetNbrNId(e), Node.GetNbrNId(e));
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); }
RetVal=false;
}
if (e > 0 && prevNId == Node.GetNbrNId(e)) {
const TStr Msg = TStr::Fmt("Node %d has duplicate edge %d --> %d.",
Node.GetId(), Node.GetId(), Node.GetNbrNId(e));
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); }
RetVal=false;
}
prevNId = Node.GetNbrNId(e);
}
}
int EdgeCnt = 0;
for (TEdgeI EI = BegEI(); EI < EndEI(); EI++) { EdgeCnt++; }
if (EdgeCnt != GetEdges()) {
const TStr Msg = TStr::Fmt("Number of edges counter is corrupted: GetEdges():%d, EdgeCount:%d.", GetEdges(), EdgeCnt);
if (ThrowExcept) { EAssertR(false, Msg); } else { ErrNotify(Msg.CStr()); }
RetVal=false;
}
return RetVal;
}
开发者ID:arbenson,项目名称:snap,代码行数:36,代码来源:graph.cpp
示例18: RestorePreferences
int RestorePreferences(void)
{
int version;
FILE *in;
struct xmlNode *root;
struct xmlNode *nodes, *children;
struct xmlAttr *attribs;
char *p;
char name[256];
if (!generalProject.profiles)
generalProject.profiles = calloc(1, sizeof(PROFILE));
GetUserDataPath(name);
strcat(name, PREFFILE);
in = fopen(name, "r");
if (!in)
{
LoadDefaultRules();
return 0;
}
root = xmlReadFile(in);
fclose(in);
if (!root || !IsNode(root, "UIPREFS"))
{
LoadDefaultRules();
return 0;
}
nodes = root->children;
while (nodes)
{
if (IsNode(nodes, "VERSION"))
{
struct xmlAttr *attribs = nodes->attribs;
while (attribs)
{
if (IsAttrib(attribs, "ID"))
version = atoi(attribs->value);
attribs = attribs->next;
}
}
else if (IsNode(nodes, "PROPERTIES"))
RestoreGeneralProps(nodes, version);
else if (IsNode(nodes, "MEMWND"))
RestoreMemoryWindowSettings(nodes, version);
else if (IsNode(nodes, "FIND"))
RestoreFindflags(nodes, version);
else if (IsNode(nodes, "PLACEMENT"))
RestorePlacement(nodes, version);
else if (IsNode(nodes, "CUSTOMCOLORS"))
RestoreCustomColors(nodes, version);
else if (IsNode(nodes, "RULES"))
RestoreBuildRules(nodes, version);
nodes = nodes->next;
}
xmlFree(root);
PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
return 1;
}
开发者ID:jossk,项目名称:OrangeC,代码行数:57,代码来源:slprefs.c
示例19: IAssert
// add a node from a vector pool
// (use TUNGraph::IsOk to check whether the graph is consistent)
int TUNGraph::AddNode(const int& NId, const TVecPool<TInt>& Pool, const int& NIdVId) {
IAssert(NId != -1);
IAssertR(! IsNode(NId), TStr::Fmt("NodeId %d already exists", NId));
MxNId = TMath::Mx(NId+1, MxNId());
TNode& Node = NodeH.AddDat(NId);
Node.Id = NId;
Node.NIdV.GenExt(Pool.GetValVPt(NIdVId), Pool.GetVLen(NIdVId));
Node.NIdV.Sort();
return NId;
}
开发者ID:SherlockYang,项目名称:Archive,代码行数:12,代码来源:graph.cpp
示例20: IAssertR
// Add a node of ID NId to the graph.
int TUNGraph::AddNode(int NId) {
if (NId == -1) {
NId = MxNId; MxNId++;
} else {
IAssertR(!IsNode(NId), TStr::Fmt("NodeId %d already exists", NId));
MxNId = TMath::Mx(NId+1, MxNId());
}
NodeH.AddDat(NId, TNode(NId));
return NId;
}
开发者ID:arbenson,项目名称:snap,代码行数:11,代码来源:graph.cpp
注:本文中的IsNode函数示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论