Skip to content

Commit 6f454f2

Browse files
Merge branch 'master' into pr/weilycoder/134
2 parents c696bdc + aa1b6e7 commit 6f454f2

File tree

11 files changed

+831
-377
lines changed

11 files changed

+831
-377
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
config.py
22
*.in
33
*.out
4+
*.exe
45

56
# Created by .ignore support plugin (hsz.mobi)
67
### Python template
@@ -133,5 +134,7 @@ target/
133134
# Pycharm
134135
venv/
135136

137+
*.DS_Store
138+
136139
# VS Code
137-
.vscode/
140+
.vscode

.pylintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[MASTER]
2+
py-version=3.5
3+
disable=R0902,R0913,R0917

cyaron/__init__.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@
55
"""
66

77
from __future__ import absolute_import
8+
9+
from random import choice, randint, random, randrange, uniform
10+
11+
#from .visual import visualize
12+
from . import log
13+
from .compare import Compare
14+
from .consts import *
15+
from .graph import Edge, Graph
816
from .io import IO
9-
from .graph import Graph, Edge
10-
from .string import String
17+
from .math import *
18+
from .merger import Merger
19+
from .polygon import Polygon
1120
from .sequence import Sequence
21+
from .string import String
1222
from .utils import *
13-
from .consts import *
1423
from .vector import Vector
15-
from .polygon import Polygon
16-
from .compare import Compare
17-
from .math import *
18-
from .merger import Merger
19-
#from .visual import visualize
20-
from . import log
21-
from random import randint, randrange, uniform, choice, random

cyaron/compare.py

Lines changed: 105 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import absolute_import, print_function
2-
from cyaron import IO, log
2+
from .io import IO
3+
from . import log
34
from cyaron.utils import *
45
from cyaron.consts import *
56
from cyaron.graders import CYaRonGraders
@@ -17,7 +18,7 @@ def __init__(self, name, mismatch):
1718
self.mismatch = mismatch
1819

1920
def __str__(self):
20-
return 'In program: \'{}\'. {}'.format(self.name,self.mismatch)
21+
return "In program: '{}'. {}".format(self.name, self.mismatch)
2122

2223

2324
class Compare:
@@ -37,7 +38,7 @@ def __process_file(file):
3738
file.output_file.seek(0)
3839
return file.output_filename, file.output_file.read()
3940
else:
40-
with open(file, "r", newline='\n') as f:
41+
with open(file, "r", newline="\n") as f:
4142
return file, f.read()
4243

4344
@staticmethod
@@ -50,26 +51,43 @@ def __normal_max_workers(workers):
5051

5152
@classmethod
5253
def output(cls, *files, **kwargs):
53-
kwargs = unpack_kwargs('output', kwargs, ('std', ('grader', DEFAULT_GRADER), ('max_workers', -1),
54-
('job_pool', None), ('stop_on_incorrect', None)))
55-
std = kwargs['std']
56-
grader = kwargs['grader']
57-
max_workers = kwargs['max_workers']
58-
job_pool = kwargs['job_pool']
59-
if kwargs['stop_on_incorrect'] is not None:
54+
kwargs = unpack_kwargs(
55+
"output",
56+
kwargs,
57+
(
58+
"std",
59+
("grader", DEFAULT_GRADER),
60+
("max_workers", -1),
61+
("job_pool", None),
62+
("stop_on_incorrect", None),
63+
),
64+
)
65+
std = kwargs["std"]
66+
grader = kwargs["grader"]
67+
max_workers = kwargs["max_workers"]
68+
job_pool = kwargs["job_pool"]
69+
if kwargs["stop_on_incorrect"] is not None:
6070
log.warn("parameter stop_on_incorrect is deprecated and has no effect.")
6171

6272
if (max_workers is None or max_workers >= 0) and job_pool is None:
6373
max_workers = cls.__normal_max_workers(max_workers)
6474
try:
6575
from concurrent.futures import ThreadPoolExecutor
76+
6677
with ThreadPoolExecutor(max_workers=max_workers) as job_pool:
67-
return cls.output(*files, std=std, grader=grader, max_workers=max_workers, job_pool=job_pool)
78+
return cls.output(
79+
*files,
80+
std=std,
81+
grader=grader,
82+
max_workers=max_workers,
83+
job_pool=job_pool
84+
)
6885
except ImportError:
6986
pass
7087

7188
def get_std():
7289
return cls.__process_file(std)[1]
90+
7391
if job_pool is not None:
7492
std = job_pool.submit(get_std).result()
7593
else:
@@ -86,61 +104,118 @@ def do(file):
86104

87105
@classmethod
88106
def program(cls, *programs, **kwargs):
89-
kwargs = unpack_kwargs('program', kwargs, ('input', ('std', None), ('std_program', None),
90-
('grader', DEFAULT_GRADER), ('max_workers', -1),
91-
('job_pool', None), ('stop_on_incorrect', None)))
92-
input = kwargs['input']
93-
std = kwargs['std']
94-
std_program = kwargs['std_program']
95-
grader = kwargs['grader']
96-
max_workers = kwargs['max_workers']
97-
job_pool = kwargs['job_pool']
98-
if kwargs['stop_on_incorrect'] is not None:
107+
kwargs = unpack_kwargs(
108+
"program",
109+
kwargs,
110+
(
111+
"input",
112+
("std", None),
113+
("std_program", None),
114+
("grader", DEFAULT_GRADER),
115+
("max_workers", -1),
116+
("job_pool", None),
117+
("stop_on_incorrect", None),
118+
),
119+
)
120+
input = kwargs["input"]
121+
std = kwargs["std"]
122+
std_program = kwargs["std_program"]
123+
grader = kwargs["grader"]
124+
max_workers = kwargs["max_workers"]
125+
job_pool = kwargs["job_pool"]
126+
if kwargs["stop_on_incorrect"] is not None:
99127
log.warn("parameter stop_on_incorrect is deprecated and has no effect.")
100128

101129
if (max_workers is None or max_workers >= 0) and job_pool is None:
102130
max_workers = cls.__normal_max_workers(max_workers)
103131
try:
104132
from concurrent.futures import ThreadPoolExecutor
133+
105134
with ThreadPoolExecutor(max_workers=max_workers) as job_pool:
106-
return cls.program(*programs, input=input, std=std, std_program=std_program, grader=grader, max_workers=max_workers, job_pool=job_pool)
135+
return cls.program(
136+
*programs,
137+
input=input,
138+
std=std,
139+
std_program=std_program,
140+
grader=grader,
141+
max_workers=max_workers,
142+
job_pool=job_pool
143+
)
107144
except ImportError:
108145
pass
109146

110147
if not isinstance(input, IO):
111-
raise TypeError("expect {}, got {}".format(type(IO).__name__, type(input).__name__))
148+
raise TypeError(
149+
"expect {}, got {}".format(type(IO).__name__, type(input).__name__)
150+
)
112151
input.flush_buffer()
113152
input.input_file.seek(0)
114153

115154
if std_program is not None:
155+
116156
def get_std():
117-
with open(os.dup(input.input_file.fileno()), 'r', newline='\n') as input_file:
118-
content = make_unicode(subprocess.check_output(std_program, shell=(not list_like(std_program)), stdin=input.input_file, universal_newlines=True))
157+
with open(
158+
os.dup(input.input_file.fileno()), "r", newline="\n"
159+
) as input_file:
160+
content = make_unicode(
161+
subprocess.check_output(
162+
std_program,
163+
shell=(not list_like(std_program)),
164+
stdin=input.input_file,
165+
universal_newlines=True,
166+
)
167+
)
119168
input_file.seek(0)
120169
return content
170+
121171
if job_pool is not None:
122172
std = job_pool.submit(get_std).result()
123173
else:
124174
std = get_std()
125175
elif std is not None:
176+
126177
def get_std():
127178
return cls.__process_file(std)[1]
179+
128180
if job_pool is not None:
129181
std = job_pool.submit(get_std).result()
130182
else:
131183
std = get_std()
132184
else:
133-
raise TypeError('program() missing 1 required non-None keyword-only argument: \'std\' or \'std_program\'')
185+
raise TypeError(
186+
"program() missing 1 required non-None keyword-only argument: 'std' or 'std_program'"
187+
)
134188

135189
def do(program_name):
136190
timeout = None
137-
if list_like(program_name) and len(program_name) == 2 and int_like(program_name[-1]):
191+
if (
192+
list_like(program_name)
193+
and len(program_name) == 2
194+
and int_like(program_name[-1])
195+
):
138196
program_name, timeout = program_name
139-
with open(os.dup(input.input_file.fileno()), 'r', newline='\n') as input_file:
197+
with open(
198+
os.dup(input.input_file.fileno()), "r", newline="\n"
199+
) as input_file:
140200
if timeout is None:
141-
content = make_unicode(subprocess.check_output(program_name, shell=(not list_like(program_name)), stdin=input_file, universal_newlines=True))
201+
content = make_unicode(
202+
subprocess.check_output(
203+
program_name,
204+
shell=(not list_like(program_name)),
205+
stdin=input_file,
206+
universal_newlines=True,
207+
)
208+
)
142209
else:
143-
content = make_unicode(subprocess.check_output(program_name, shell=(not list_like(program_name)), stdin=input_file, universal_newlines=True, timeout=timeout))
210+
content = make_unicode(
211+
subprocess.check_output(
212+
program_name,
213+
shell=(not list_like(program_name)),
214+
stdin=input_file,
215+
universal_newlines=True,
216+
timeout=timeout,
217+
)
218+
)
144219
input_file.seek(0)
145220
cls.__compare_two(program_name, content, std, grader)
146221

cyaron/graph.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ def __init__(self, point_count, directed=False):
4343
"""
4444
self.directed = directed
4545
self.edges = [[] for i in range(point_count + 1)]
46+
47+
def edge_count(self):
48+
"""edge_count(self) -> int
49+
Return the count of the edges in the graph.
50+
"""
51+
cnt = sum(len(node) for node in self.edges)
52+
if not self.directed:
53+
cnt //= 2
54+
return cnt
4655

4756
def to_matrix(self, **kwargs):
4857
"""to_matrix(self, **kwargs) -> list[list[Any]]
@@ -280,6 +289,11 @@ def graph(point_count, edge_count, **kwargs):
280289
directed = kwargs.get("directed", False)
281290
self_loop = kwargs.get("self_loop", True)
282291
repeated_edges = kwargs.get("repeated_edges", True)
292+
if not repeated_edges:
293+
max_edge = Graph._calc_max_edge(point_count, directed, self_loop)
294+
if edge_count > max_edge:
295+
raise Exception("the number of edges of this kind of graph which has %d vertexes must be less than or equal to %d." % (point_count, max_edge))
296+
283297
weight_limit = kwargs.get("weight_limit", (1, 1))
284298
if not list_like(weight_limit):
285299
weight_limit = (1, weight_limit)
@@ -311,7 +325,7 @@ def graph(point_count, edge_count, **kwargs):
311325
@staticmethod
312326
def DAG(point_count, edge_count, **kwargs):
313327
"""DAG(point_count, edge_count, **kwargs) -> Graph
314-
Factory method. Return a graph with point_count vertexes and edge_count edges.
328+
Factory method. Return a directed connected graph with point_count vertexes and edge_count edges.
315329
int point_count -> the count of vertexes
316330
int edge_count -> the count of edges
317331
**kwargs(Keyword args):
@@ -332,6 +346,11 @@ def DAG(point_count, edge_count, **kwargs):
332346
self_loop = kwargs.get("self_loop", False) # DAG default has no loop
333347
repeated_edges = kwargs.get("repeated_edges", True)
334348
loop = kwargs.get("loop", False)
349+
if not repeated_edges:
350+
max_edge = Graph._calc_max_edge(point_count, not loop, self_loop)
351+
if edge_count > max_edge:
352+
raise Exception("the number of edges of this kind of graph which has %d vertexes must be less than or equal to %d." % (point_count, max_edge))
353+
335354
weight_limit = kwargs.get("weight_limit", (1, 1))
336355
if not list_like(weight_limit):
337356
weight_limit = (1, weight_limit)
@@ -377,7 +396,7 @@ def DAG(point_count, edge_count, **kwargs):
377396
@staticmethod
378397
def UDAG(point_count, edge_count, **kwargs):
379398
"""UDAG(point_count, edge_count, **kwargs) -> Graph
380-
Factory method. Return a graph with point_count vertexes and edge_count edges.
399+
Factory method. Return a undirected connected graph with point_count vertexes and edge_count edges.
381400
int point_count -> the count of vertexes
382401
int edge_count -> the count of edges
383402
**kwargs(Keyword args):
@@ -396,6 +415,11 @@ def UDAG(point_count, edge_count, **kwargs):
396415

397416
self_loop = kwargs.get("self_loop", True)
398417
repeated_edges = kwargs.get("repeated_edges", True)
418+
if not repeated_edges:
419+
max_edge = Graph._calc_max_edge(point_count, False, self_loop)
420+
if edge_count > max_edge:
421+
raise Exception("the number of edges of this kind of graph which has %d vertexes must be less than or equal to %d." % (point_count, max_edge))
422+
399423
weight_limit = kwargs.get("weight_limit", (1, 1))
400424
if not list_like(weight_limit):
401425
weight_limit = (1, weight_limit)
@@ -430,6 +454,18 @@ def UDAG(point_count, edge_count, **kwargs):
430454
i += 1
431455

432456
return graph
457+
458+
@staticmethod
459+
def connected(point_count, edge_count, directed=False, **kwargs):
460+
"""connected(point_count, edge_count, **kwargs) -> Graph
461+
Factory method. Return a connected graph with point_count vertexes
462+
int point_count -> the count of vertexes
463+
bool directed -> whether the graph is directed
464+
"""
465+
if directed:
466+
return Graph.DAG(point_count, edge_count, **kwargs)
467+
else:
468+
return Graph.UDAG(point_count, edge_count, **kwargs)
433469

434470
@staticmethod
435471
def hack_spfa(point_count, **kwargs):
@@ -481,6 +517,15 @@ def hack_spfa(point_count, **kwargs):
481517
graph.add_edge(u, v, weight=weight_gen())
482518

483519
return graph
520+
521+
@staticmethod
522+
def _calc_max_edge(point_count, directed, self_loop):
523+
max_edge = point_count * (point_count - 1)
524+
if not directed:
525+
max_edge //= 2
526+
if self_loop:
527+
max_edge += point_count
528+
return max_edge
484529

485530

486531
T = TypeVar('T')

0 commit comments

Comments
 (0)