pgvm 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pgvm/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ from .editable_graph import EditableGraph
2
+
3
+ __all__=[
4
+ EditableGraph,
5
+ ]
pgvm/editable_graph.py ADDED
@@ -0,0 +1,303 @@
1
+ import graphviz
2
+
3
+ class EditableGraph():
4
+ """
5
+ @Summ: 編集可能なgraph構造を与えるclass.
6
+
7
+ @Desc:
8
+ - node番号は非負整数である。負の値はerror用。
9
+ """
10
+ ROOT_NODE=0
11
+ NEW_NODE=1
12
+ DELETE_NODE=2
13
+ NEW_EDGE_LABEL="new"
14
+ DELETE_EDGE_LABEL="delete"
15
+ PATH_DELIMITER="/"
16
+
17
+
18
+ @classmethod
19
+ def __initializeGraph(cls):
20
+ """
21
+ @Summ: 初期状態のgraphを出力する関数。
22
+ """
23
+ initGraph={cls.ROOT_NODE:{"new":cls.NEW_NODE, "delete":cls.DELETE_NODE},
24
+ cls.NEW_NODE:{},
25
+ cls.DELETE_NODE:{}
26
+ }
27
+ return initGraph
28
+
29
+
30
+ def __init__(self,data,connectingNode:int,program:list=None):
31
+ """
32
+ @Summ: constructor.
33
+
34
+ @InsVars:
35
+ data:
36
+ @Summ: {node番号(int):{edgeLabel(str):node番号(int)}}。
37
+ @Type: Dict
38
+ maxNodeIdx:
39
+ @Summ: node番号の最大値を記録する。
40
+ @Type: Int
41
+ program:
42
+ @Summ: programのdataを入れる。
43
+ @Type: Str型二次元配列。
44
+ programCounter:
45
+ @Summ: 次に実行するprogramの行番号を記録する。
46
+ @Desc: 例外messageを出すために必要。
47
+ @Type: Int
48
+ programLength:
49
+ @Summ: 次に実行するprogramの行数を記録する。
50
+ @Type: Int
51
+ """
52
+ initGraph=self.__initializeGraph()
53
+ initGraph[self.ROOT_NODE]["file"]=connectingNode
54
+ initGraph|=data
55
+ self.data=initGraph
56
+ self.maxNodeIdx=None
57
+ self.program=program
58
+ self.programCounter=0
59
+ if(program is None):
60
+ self.programLength=0
61
+ else:
62
+ self.proramLength=len(program)
63
+
64
+ def loadProgramCSV(self,csvFile):
65
+ """
66
+ @Summ: programが書かれたCSV fileをloadする関数。
67
+
68
+ @Args:
69
+ csvFile:
70
+ @Summ: programが書かれたcsv file名。
71
+ @SemType: str型の二次元配列。
72
+ """
73
+ with open(csvFile,mode="r",encoding="utf-8") as f:
74
+ lineList=f.readlines()
75
+ programData=[]
76
+ for line in lineList:
77
+ if(line[-1]=="\n"):
78
+ notBreakLine=line[:-1]
79
+ else:
80
+ notBreakLine=line
81
+ argList=notBreakLine.split(",")
82
+ programData.append(argList)
83
+ self.program=programData
84
+ self.programLength=len(programData)
85
+
86
+ def __issueNewNode(self):
87
+ """
88
+ @Summ: 新しいnode番号を発行する関数。
89
+
90
+ @Desc: 最大値を利用して新しい番号を生成している。
91
+
92
+ @Returns:
93
+ @Summ: 新しいnode番号。
94
+ @Type: Int
95
+ """
96
+ if(self.maxNodeIdx is None):
97
+ self.maxNodeIdx=max(self.data.keys())
98
+ newNodeIdx=self.maxNodeIdx+1
99
+ self.maxNodeIdx=newNodeIdx
100
+ self.data[newNodeIdx]={}
101
+ return newNodeIdx
102
+
103
+ def visualize(self,filename):
104
+ """
105
+ @Summ: graphvizで可視化する関数。
106
+ """
107
+ graph=graphviz.Digraph()
108
+ graph.filename=filename
109
+ graph.format="svg"
110
+ graph.attr("graph",rankdir="LR")
111
+ for nodeIdx,edgeDict in self.data.items():
112
+ # print(nodeIdx)
113
+ graph.node(str(nodeIdx))
114
+ for edgeLabel,destNode in edgeDict.items():
115
+ graph.edge(tail_name=str(nodeIdx), head_name=str(destNode), label=edgeLabel)
116
+ graph.render()
117
+
118
+ def accessNode(self,path:list):
119
+ """
120
+ @Summ: pathからedgeを参照する関数。
121
+
122
+ @Args:
123
+ path:
124
+ @Summ: 参照するedge.
125
+ @SemType: Str型List.
126
+ @Returns:
127
+ - @Summ: nodeの到達履歴。
128
+ @Desc: 到達不可能になったらそこで終了する。
129
+ @Type: Int型List
130
+ - @Summ: 使わなかったedgeLabelの数。この数字を未到達度と呼ぶ。
131
+ @Desc: 0で到達完了を表す。
132
+ @Type: Int
133
+ """
134
+ history=[self.ROOT_NODE]
135
+ curEdgeDict=self.data[self.ROOT_NODE]
136
+ pathLength=len(path)
137
+ unreached=pathLength
138
+ for i in range(pathLength):
139
+ edgeLabel=path[i]
140
+ curNode=curEdgeDict.get(edgeLabel)
141
+ if(curNode is None):
142
+ break
143
+ history.append(curNode)
144
+ curEdgeDict=self.data[curNode]
145
+ unreached-=1
146
+ return history,unreached
147
+
148
+ def changeEdgeDestination(self,oldPath,newPath):
149
+ """
150
+ @Summ: edgeの終点を変更する関数。
151
+
152
+ @Desc:
153
+ - nodeの生成を伴わないedgeの生成まではできる。
154
+ - 始点と終点が同じ辺(二重辺)は禁止。
155
+
156
+ @Args:
157
+ oldPath:
158
+ @Summ: 現在のedgeの終着点。
159
+ @Desc:
160
+ - 未到達度0の時は、既存のedgeの終点を付け替える作業。
161
+ - 未到達度1の時は、新しいedgeLabelを生成する。
162
+ - それ以上の未到達度は受け付けない。
163
+ @SemType: Str型List.
164
+ newPath:
165
+ @Summ: edgeの新しい終着点を指定する。
166
+ @Desc: 未到達度0のpathしか受け付けない。
167
+ @SemType: Str型List.
168
+ """
169
+ oldDestHistory,oldUnused=self.accessNode(oldPath)
170
+ lastEdgeLabel=oldPath[-1]
171
+ if(oldUnused==0):
172
+ edgeStartNode=oldDestHistory[-2]
173
+ elif(oldUnused==1):
174
+ edgeStartNode=oldDestHistory[-1]
175
+ else:
176
+ raise RuntimeError(f"line: {self.programCounter}:\n\t{oldPath} is not accessable.")
177
+ newDestHistory,newUnused=self.accessNode(newPath)
178
+ if(newUnused>0):
179
+ raise RuntimeError(f"line: {self.programCounter}:\n\t{newPath} is not accessable.")
180
+ newEndNode=newDestHistory[-1]
181
+ edgeInfo=self.data[edgeStartNode]
182
+ if(newEndNode in edgeInfo.values()):
183
+ raise RuntimeError(f"line: {self.programCounter}:\n\t Edge endpoint is duplicated.") #既存のedgeの終端が被る。
184
+ self.data[edgeStartNode][lastEdgeLabel]=newEndNode
185
+
186
+ def deleteEdge(self,path):
187
+ """
188
+ @Summ: 到達可能なedgeを削除する関数。
189
+
190
+ @Args:
191
+ path:
192
+ @Summ: 削除するedge.
193
+ @SemType: Str型List.
194
+ """
195
+ lastNodePath=path[:-1]
196
+ lastEdge=path[-1]
197
+ history,unreached=self.accessNode(lastNodePath)
198
+ if(unreached==0):
199
+ lastNode=history[-1]
200
+ del self.data[lastNode][lastEdge]
201
+ else:
202
+ raise RuntimeError(f"line: {self.programCounter}:\n\t{path} is not accessable.")
203
+
204
+ def generateEdge(self,path):
205
+ """
206
+ @Summ: nodeの生成を伴うedgeの生成を行う関数。
207
+
208
+ @Args:
209
+ path:
210
+ @Summ: 新しく生成するpath.
211
+ @Desc: 未到達度=1である必要がある。
212
+ @SemType: Str型List.
213
+ """
214
+ history,unreached=self.accessNode(path)
215
+ if(unreached!=1):
216
+ raise RuntimeError(f"line: {self.programCounter}:\n\t{path} is not accessable.")
217
+ lastEdge=path[-1]
218
+ lastNode=history[-1]
219
+ newNode=self.__issueNewNode()
220
+ self.data[lastNode][lastEdge]=newNode
221
+
222
+ def execute(self):
223
+ """
224
+ @Summ: programを実行する関数。
225
+ """
226
+ self.programCounter=0
227
+ while(True):
228
+ if(self.programLength<=self.programCounter):
229
+ break
230
+ argList=self.program[self.programCounter]
231
+ if(argList[0]=="cp"):
232
+ self.executeCopy(argList[1],argList[2])
233
+ self.programCounter=int(argList[3])
234
+ continue
235
+ elif(argList[0]=="if"):
236
+ isSame=self.executeIf(argList[1],argList[2])
237
+ if(isSame):
238
+ self.programCounter=int(argList[3])
239
+ else:
240
+ self.programCounter=int(argList[4])
241
+ return
242
+
243
+ def executeCopy(self,path1,path2):
244
+ """
245
+ @Summ: copy文を実行する関数。
246
+
247
+ @Args:
248
+ path1:
249
+ @Summ: copy文の第一引数。編集するpathを表す。
250
+ @Type: Str
251
+ path2:
252
+ @Summ: copy文の第二引数。上書きするpathを表す。
253
+ @Type: Str
254
+ """
255
+ path1EdgeList=path1.split(self.PATH_DELIMITER)
256
+ if(path2==self.NEW_EDGE_LABEL):
257
+ self.generateEdge(path1EdgeList)
258
+ elif(path2==self.DELETE_EDGE_LABEL):
259
+ self.deleteEdge(path1EdgeList)
260
+ else:
261
+ path2EdgeList=path2.split(self.PATH_DELIMITER)
262
+ self.changeEdgeDestination(path1EdgeList,path2EdgeList)
263
+
264
+ def executeIf(self,path1,path2):
265
+ """
266
+ @Summ: if文を実行する関数。
267
+
268
+ @Desc:
269
+ - path1==未到達度1∧path2==DELETE_NODEの時、edgeが存在しない時にTrueを出力する。
270
+
271
+ @Args:
272
+ path1:
273
+ @Summ: if文の第一引数。比較するpathその1。
274
+ @Type: Str
275
+ path2:
276
+ @Summ: if文の第二引数。比較するpathその2。
277
+ @Type: Str
278
+ @Returns:
279
+ @Summ: 同じ値の時にTrue.
280
+ @Type: Bool
281
+ """
282
+ path1EdgeList=path1.split(self.PATH_DELIMITER)
283
+ path1History,path1unreached=self.accessNode(path1EdgeList)
284
+ if(path2==self.DELETE_EDGE_LABEL):
285
+ if(path1unreached==0):
286
+ return False
287
+ elif(path1unreached==1):
288
+ return True
289
+ else:
290
+ raise RuntimeError(f"line {self.programCounter}:\n\t{path2} is not accessable.")
291
+ path2EdgeList=path2.split(self.PATH_DELIMITER)
292
+ path2History,path2unreached=self.accessNode(path2EdgeList)
293
+ if(path1unreached!=0):
294
+ raise RuntimeError(f"line {self.programCounter}:\n\t{path1} is not accessable.")
295
+ if(path2unreached!=0):
296
+ raise RuntimeError(f"line {self.programCounter}:\n\t{path2} is not accessable.")
297
+ path1LastNode=path1History[-1]
298
+ path2LastNode=path2History[-1]
299
+ if(path1LastNode==path2LastNode):
300
+ return True
301
+ else:
302
+ return False
303
+
@@ -0,0 +1,31 @@
1
+ Metadata-Version: 2.4
2
+ Name: pgvm
3
+ Version: 0.1.0
4
+ Summary: PGVM is an abbreviation for Pointer Graph Virtual Machine.
5
+ Author-email: masaniki <masaniki.software@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/masaniki/python-pgvm
8
+ Project-URL: Issues, https://github.com/masaniki/python-pgvm/issues
9
+ Keywords: graph,node,edge,automaton,processor
10
+ Classifier: Development Status :: 1 - Planning
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Natural Language :: Japanese
14
+ Classifier: Natural Language :: English
15
+ Classifier: Intended Audience :: Information Technology
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE.txt
19
+ Requires-Dist: PyYAML
20
+ Requires-Dist: graphviz
21
+ Dynamic: license-file
22
+
23
+ # Introduction
24
+
25
+ This is a introduction.
26
+
27
+ Original document is [HERE](docs/README_JP.md).
28
+
29
+ # Installing
30
+
31
+ `pip install pgvm`
@@ -0,0 +1,7 @@
1
+ pgvm/__init__.py,sha256=GY_Au96x1eHCwTyFeo2u7ECsEo1nLIgB30UxSTX774g,75
2
+ pgvm/editable_graph.py,sha256=c40N4VQXM2JYudWl7-J7P6qvrpCHV2B9FBPwFH2nPJ0,9389
3
+ pgvm-0.1.0.dist-info/licenses/LICENSE.txt,sha256=7oOMsj5XGQQ_SippluC7AuCMB_Vrujo2jqT0QkRkN64,1061
4
+ pgvm-0.1.0.dist-info/METADATA,sha256=4wMpxOPO5CgCtou0yOhwme0NgwmZo8BpC1hoUTKY7OQ,965
5
+ pgvm-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
6
+ pgvm-0.1.0.dist-info/top_level.txt,sha256=rparoIlC_FHLpXxMvM7xTajsiJYPX0ghdwMbPK3XO3w,5
7
+ pgvm-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,7 @@
1
+ Copyright 2026 masaniki
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ pgvm